[c++] pointers, extern

Pagina: 1
Acties:
  • 146 views sinds 30-01-2008
  • Reageer

  • phaas
  • Registratie: Augustus 2001
  • Laatst online: 23-01-2025
Hallo!

Ik zit met een vervelend probleem, nl:
-> Ik heb een class met een aantal puur-virtuele functies
-> Dezelfde class bevat een statisch member linked-list die pointers opslaat van z'n eigen type
-> Een aantal classen 'inheriten' (nederlands?) deze class en implenteren de virtuele functies, daarna wordt een pointer naar een instantie hiervan aan de linked-list toegevoegd
-> Vervolgens pak ik een pointer uit de linked-list waarbij ik wél de niet-virtuele functies van het object aan kan roepen maar de virtuele functies leveren een segfault op....
Heb ik het zo een beetje duidelijk geschetst?

Kan het er verder aan liggen dat het object gecreeërd wordt in een C abi functie (extern "C" {..}) vanuit een plugin?

Bedankt!
Barry

  • PrisonerOfPain
  • Registratie: Januari 2003
  • Laatst online: 07-04 13:41
offtopic:
inheriten -> overerven

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 12-05 22:23

curry684

left part of the evil twins

Ik snap er geen bal van zonder wat code :?

En vermeld trouwens ook even welke compiler je gebruikt, kan wonderen doen.

[ Voor 48% gewijzigd door curry684 op 17-02-2004 21:47 ]

Professionele website nodig?


Verwijderd

Roep je de virtuele functies direct aan vanuit de constructor van je child class?

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 01:00

.oisyn

Moderator Devschuur®

Demotivational Speaker

Nouk: je bedoelt zeker vanuit de parent class, andersom werkt namelijk prima.
Maar dan nog levert dat meestal wel een compiler warning dan wel link error op

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • phaas
  • Registratie: Augustus 2001
  • Laatst online: 23-01-2025
Verwijderd schreef op 17 februari 2004 @ 21:33:
Roep je de virtuele functies direct aan vanuit de constructor van je child class?
Nee.

Verder was ik even onvolledig:
Platform: Linux, gcc3
code wordt wat moeilijk, het is een beetje veel.... ik kijk morgen wel even voor wat pseudo code, oké?

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
Het kan fout gaan als je een non-virtual call doet naar de virtual functies
code:
1
ptr->Base::foo();

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 01:00

.oisyn

Moderator Devschuur®

Demotivational Speaker

Waarom kan het dan fout gaan :? Dat is toch gewoon een directe call zonder naar de vtable te kijken? Het lijkt me dan ook gewoon een normale aanroep die verder niet fout gaat. Als er geen implementatie is dan krijg je een link error, en anders wordt de methode gewoon op een normale (non-virtual) manier aangeroepen. Waarom zou je dan een segfault oid kunnen krijgen?

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • phaas
  • Registratie: Augustus 2001
  • Laatst online: 23-01-2025
MSalters schreef op 17 februari 2004 @ 22:35:
Het kan fout gaan als je een non-virtual call doet naar de virtual functies
code:
1
ptr->Base::foo();
Is niet het geval.

Hier even een code met dezelfde opstelling, voor de hand liggende implentatie stukken zijn weggelaten:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
// Eerst de basis class, Base
// Deze heeft drie functies: lijst behouden (statisch), catalogiseren, abstracte interface

class Base
{
    public:
    // Het object moet een naam voor in de lijst
    Base(const QString &name) { m_name = name; }
    virtual ~Base();

    // Enige non-virtueele functie dient om te naam op te vragen
    QString name();

    virtual bool eenVirtueeleFunctie() =0;

    // functie om een 'Base' toe te voegen aan de linked list
    static void register(Base *);
    // zoek een 'Base' op naam
    static Base *fetch(const QString &name);

    private:
    QString m_name;
    static QPtrList<Base> static_linkedList;
};

// Nu de overrevende class, myClass

class myClass : public Base
{
    myClass() : Base("myClass") { }
    ~myClass();

    bool eenVirtueeleFunctie()
    {
        /** code hier */
    }
};

// Dit staat zo ongeveer in de plugin

extern "C"
{
    void init()
    {
        Base::register(new myClass());
    }
}

// Nu een stuk voorbeeld code dat een 'myClass' probeert te gebruiken

{
    Base *a = Base::fetch("myClass");

    // eerst controleren we of ie wel bestaat
    if(!a)
        return;

    // ja dus, dat roepen we eerst een non-virtueele functie aan uit 'Base'

    cout << a->name() << endl;

    // prima, nu roepen we een non-virtueele functie aan 

    if(a->eenVirtueeleFunctie())
        ...  // fuck, segfault 

}


Dit blijft een raar probleem in mijn ogen, ik zou het vooralsnog op de extern "C" gooien, misschien omdat C niks van virtueele functies afweet.
Maar aan de andere kant heb ik dit soort zaken al vaker gedaan, met success.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 01:00

.oisyn

Moderator Devschuur®

Demotivational Speaker

ik zou het vooralsnog op de extern "C" gooien
dat heeft er helemaal niets mee te maken, dit geeft alleen maar aan dat de functies in dat extern "C" block een C linkage krijgen, verder niet. Weet je zeker dat je de segfault krijgt bij de aanroep van eenVirtueleFunctie, en niet daarvoor al, of juist erin?

Ik vermoed een shared memory probleem. Link je wel tegen een shared runtime? En is die library waar die QString in zit ook shared?

PS. "virtuele" schrijf je met in totaal 2 e's, niet 3 ;)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • phaas
  • Registratie: Augustus 2001
  • Laatst online: 23-01-2025
.oisyn schreef op 17 februari 2004 @ 23:45:
[...]

dat heeft er helemaal niets mee te maken, dit geeft alleen maar aan dat de functies in dat extern "C" block een C linkage krijgen, verder niet. Weet je zeker dat je de segfault krijgt bij de aanroep van eenVirtueleFunctie, en niet daarvoor al, of juist erin?

Ik vermoed een shared memory probleem. Link je wel tegen een shared runtime? En is die library waar die QString in zit ook shared?
eenVirtueleFunctie hoeft niet eens echt code te bevatten, de rest van de code is correct.
Ook een niet-puur virtuele functie geeft trouwens diezelfde problemen.

Qt, waar QString vandaan komt, wordt als een shared library meegelinkt. Bedoel je dat?

Watbetreft dat shared-mem, de instantie wordt gemaakt binnen een plugin en gebruikt in weer een andere plugin.
Ik gebruikt dlopen() in Linux voor die plugins, vandaar dat extern "C" verhaal...


> PS. "virtuele" schrijf je met in totaal 2 e's, niet 3 ;)
:Y)

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 12-05 22:23

curry684

left part of the evil twins

• Controleer of de pointer die je in de linked list stopt identiek is aan de pointer die je uit de search krijgt.
• Controleer dat je de class instance correct met placement new of gewone new instantieert.

Ik vermoed weet vrijwel 100% zeker dat je een corrupte vtable hebt, maar in dit stukje code kan ik niet zien hoe dat zou komen...

[ Voor 5% gewijzigd door curry684 op 18-02-2004 03:23 ]

Professionele website nodig?


  • phaas
  • Registratie: Augustus 2001
  • Laatst online: 23-01-2025
curry684 schreef op 18 februari 2004 @ 03:23:
• Controleer of de pointer die je in de linked list stopt identiek is aan de pointer die je uit de search krijgt.
• Controleer dat je de class instance correct met placement new of gewone new instantieert.

Ik vermoed weet vrijwel 100% zeker dat je een corrupte vtable hebt, maar in dit stukje code kan ik niet zien hoe dat zou komen...
• De pointer is dezelfde in de linkedlist als de oorspronkelijke
• Ik gebruik de 'gewone' new

Verder werkt de pointer op sommige punten wel, ook erg vreemd.
Als plugin #1 het object instantieert en plugin #2 probeert een virtuele functie aan te roepen komt er een segfault.
Maar als bv. plugin #1 zelf een virtuele functie aanroept gaat het wel goed.

Ik krijg ook van valgrind een rare foutmelding:
code:
1
2
3
4
5
6
7
==2348== Jump to the invalid address stated on the next line
==2348==    at 0x1000: ???
==2348==    by 0x402AC8EA: Edukitty::NetBrowser::protocol() (netbrowser.cpp:687)
==2348==    by 0x402AAD4F: Edukitty::NetBrowser::checkForValidProtocol() (netbrowser.cpp:218)
==2348==    by 0x402AC12C: Edukitty::NetBrowser::renderCurrentDir() (netbrowser.cpp:642)
==2348==    Address 0x1000 is not stack'd, malloc'd or free'd
Segmentation fault

Beetje vreemd address nietwaar?

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 12-05 22:23

curry684

left part of the evil twins

Je hebt dan echt ergens hopeloos je vtable verneukt, maar niet in deze code afaics. Kun je geen memory breakpoint zetten? Oftewel de class instantieren, en dan een write breakpoint zetten op de eerste tig bytes vanaf dat adres?

Professionele website nodig?


  • phaas
  • Registratie: Augustus 2001
  • Laatst online: 23-01-2025
curry684 schreef op 18 februari 2004 @ 10:34:
Je hebt dan echt ergens hopeloos je vtable verneukt, maar niet in deze code afaics. Kun je geen memory breakpoint zetten? Oftewel de class instantieren, en dan een write breakpoint zetten op de eerste tig bytes vanaf dat adres?
Hoe kan ik in godsnaam mijn vtable verpesten?
Zal ik een stukje 'echte' code plaatsen danmaar?

  • BoAC
  • Registratie: Februari 2003
  • Laatst online: 27-05 18:22

BoAC

Memento mori

Als je nu geen full virtual function gebruikt maar een gewone virtual function en die overload? Welke wordt er dan gebruikt in je plugin?
Misschien kent je plugin de vft niet volledig :?

  • phaas
  • Registratie: Augustus 2001
  • Laatst online: 23-01-2025
BoAC schreef op 18 februari 2004 @ 10:43:
Als je nu geen full virtual function gebruikt maar een gewone virtual function en die overload? Welke wordt er dan gebruikt in je plugin?
Misschien kent je plugin de vft niet volledig :?
Ook een niet-pure virtuele functie levert een zo'n zelfde segfault op.
De plugin kent de class zelf idd niet, maar dat moet toch geen prob zijn lijkt me.

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 12-05 22:23

curry684

left part of the evil twins

phaas schreef op 18 februari 2004 @ 10:39:
[...]
Hoe kan ik in godsnaam mijn vtable verpesten?
Mjah:
C++:
1
2
VirtualClass* MyClass = new VirtualClass;
*((int*)MyClass) = 684;

Is de meest obvious example, maar een simpele bufferoverflow of stack corruption elders kan het natuurlijk ook veroorzaken :)
Zal ik een stukje 'echte' code plaatsen danmaar?
Wordt intussen wel een idee :)

Met het feit dat non-virtual functies wel perfect werken en virtuals klappen lijkt de diagnose me duidelijk... nu nog de oorzaak :Y)

[ Voor 13% gewijzigd door curry684 op 18-02-2004 11:25 ]

Professionele website nodig?


  • phaas
  • Registratie: Augustus 2001
  • Laatst online: 23-01-2025
Oké dan, prepare :D

Eerst "Protocol", voorheen "Base"
Protocol.h:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#ifndef PROTOCOL_H
#define PROTOCOL_H

#include <qiodevice.h>
#include <qptrlist.h>
#include <qstring.h>
#include <qstringlist.h>
#include <qfile.h>

namespace Edukitty
{
  class Url;
  class EConfigDevice;
  
  class Protocol
  {
    public:
    enum DirFilter
    {
      Files,
      Folders
    };
    Protocol(const QString &name);
    virtual ~Protocol();

    virtual bool getFile(QIODevice *, const QString& filepath) =0;
    
    virtual bool cacheLocal(QFile *, const QString& filepath) =0;

    virtual bool getEConfig(EConfigDevice *, const QString &filepath) =0;

    virtual bool mkdir(const QString &) =0;
    virtual bool remove(const QString &) =0;
    virtual bool rmdir(const QString &) =0;
    virtual bool cd(const QString &) =0;
    virtual bool cdUp() =0;
    virtual QString currentDir() =0;
    virtual QStringList ls(const QString &filter) =0;
    virtual QStringList ls(int filter) =0;
    virtual bool move(const QString &, const QString &) =0;
    virtual bool copy(const QString &, const QString &) =0;

    QString protocolName() const;
    virtual bool isValid() const;

    protected:
    void setProtocolName(const QString&);

    private:
    QString m_protocolName;

    /** Static part
    */

    public:
    static Protocol* fetchProtocol(const QString &protocolName);
    static bool registerProtocol(Protocol *);
    static bool unregisterProtocol(const QString &protocolName);
    static bool setDefaultProtocol(const QString &protocolName);
    static Protocol* defaultProtocol();
    
    static void doCleanup();

    static void printDebugMessage();
    
    private:
    static QPtrList<Protocol>* static_protocolList;
    static Protocol* static_defaultProtocol;
 
  };

};

#endif


Daarna "File", een "Protocol"
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#ifndef FILE_H
#define FILE_H

#include <protocol.h>
#include <qfile.h>
#include <qdir.h>
#include <iostream>
#include <component.h>

using namespace Edukitty;
using namespace std;

class FileProtocol : public Protocol
{
  public:
  FileProtocol();
  ~FileProtocol();

  bool getFile(QIODevice *, const QString& filepath);

  bool cacheLocal(QFile *, const QString& filepath);

  bool getEConfig(EConfigDevice *, const QString &filepath);

  bool mkdir(const QString &);
  bool remove(const QString &);
  bool rmdir(const QString &);
  bool cd(const QString &);
  bool cdUp();
  QString currentDir();
  QStringList ls(const QString &filter);
  QStringList ls(int filter);
  bool move(const QString &, const QString &);
  bool copy(const QString &, const QString &);

  bool isValid() const
  {
    cout << "FileProtocol::isValid() gets called" << endl;
    return true;
  }

  protected:
  QDir _currentDir;

};

// Dit is het plugin gedeelte, eveneens onderdeel van de File serie...

extern "C"
{
  Component* register_fileprotocol()
  {
    Protocol::registerProtocol(new FileProtocol());
    return 0;
  }
};

#endif


De implentatie van de meeste zaken is niet echt boeiend, vandaar dat ze er niet bij staan.

Nu even een stukje code dat dit zaakje gebruikt:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// m_protocol wordt in de contructor geinitialiseerd, ongv. zo:
NetBrowser::NetBrowser(..., const QString &protoName)
: m_protocol(Protocol::fetchProtocol(protoName))
{
    ...
    checkForValidProtocol();
    ...
}

// Dit is dé functie waar het als eerst fout gaat...
bool NetBrowser::checkForValidProtocol()
  {
    ifnexists(m_protocol)
      return false;
    if(!m_protocol->isValid())  // segfault hier
      return false;
    return true;
  }


Happy reading! :+

  • BoAC
  • Registratie: Februari 2003
  • Laatst online: 27-05 18:22

BoAC

Memento mori

Hoe is eigenlijk de volgorde van creeren?
Wordt eerst Component* register_fileprotocol() van File Aangeroepen?
Of eerst static QPtrList<Protocol>* static_protocolList; Aangemaakt?

Dat is me nog niet helemaal duidelijk..
Kun je dat nog ff posten?

Dat systeem wat je daar gebruikt heb ik zelf ook wel eens gemaakt dus moet verder wel kunnen ;)

[ Voor 18% gewijzigd door BoAC op 18-02-2004 11:45 ]


  • phaas
  • Registratie: Augustus 2001
  • Laatst online: 23-01-2025
BoAC schreef op 18 februari 2004 @ 11:44:
Hoe is eigenlijk de volgorde van creeren?
Wordt eerst Component* register_fileprotocol() van File Aangeroepen?
Of eerst static QPtrList* static_protocolList; Aangemaakt?

Dat is me nog niet helemaal duidelijk..
Kun je dat nog ff posten?

Dat systeem wat je daar gebruikt heb ik zelf ook wel eens gemaakt dus moet verder wel kunnen ;)
Eerst wordt de linkedlist geinstantieerd, op een later tijdstip wordt de plugin pas gelanceerd.

edit:
Wachten even, static QPtrList* static_protocolList wordt pas gealloceerd als de constructor van Protocol() voor het eerst wordt aangeroepen.

zo dus:
code:
1
2
3
4
5
6
Protocol::Protocol(const QString &name)
  {
    if(!static_protocolList)
      static_protocolList = new QPtrList<Protocol>();
    setProtocolName(name);
  }


.modbreak: kicken doen we pas na 24 uur, heb gewoon even geduld, niet iedereen is altijd online :)

[ Voor 38% gewijzigd door .oisyn op 18-02-2004 17:26 ]


  • phaas
  • Registratie: Augustus 2001
  • Laatst online: 23-01-2025
Hmmz, als ik de plugin aanroep vanuit een andere plugin werkt alles perferct :? 8)7 |:(
Dus: main -> plugin 1 -> plugin 2
main -> plugin 3
plugin 2 maakt het FileProtocol object aan en registreert dit, plugin 1 haalt een pointer op met fetchProtocol en roept viruele functies aan.
Nou is dit precies ook de definitieve situatie in mijn programma :P maar vaag is het wel natuurlijk...
Ik denk dat ik het voorlopig even zou houd al ben ik toch wel benieuwd naar hoe dit rare probleem nou toch 4 dagen debug werk gekost heeft |:( :O
Pagina: 1