virtuelle klasse und co. --> applikation crasht



  • hi, ich habe folgende seltsame situation mit abstuerzen eines C++ Programms aus dem nichts:

    (die folgende code-fragmente sind nur vereinfachte beispiele des original-codes):

    modul bi_a.h:

    class BI_A
    {
      public:
       virtual int Foo() = 0;
       virtual const std::set<int>& GetSupportedModes(void)
       { 
         static std::set<int> modes;
         if (modes.empty()) { modes.insert(1); modes.insert(2); }
          return modes; 
       }
    };
    

    modul a.h:

    class A : public BI_A
    {
      public:
         A(void);
        virtual ~A(void);
        int Foo(){return 5;}
    };
    

    modul a.cpp:

    A()
    {
    }
    ~A(void)
    {
    }
    

    modul call.cpp

    void Call( void )
    {
      static const bool check Get_A_Instance()->GetSupportedModes().end() != 
                              Get_A_Instance()->GetSupportedModes().find(2);
    }
    

    Get_A_Instance liefert mir einen Zeiger auf einen Singleton vom Typ *BI_A. Die Instanz hierzu wird bei Programmstart auf dem Heap erzeugt.

    Das seltsame ist, dass ich manchmal bei Aufruf von Call() einen Applications-Absturz bekomme.

    Gucke ich mir mit gdb und einem corefile den function-call trace an, sehe ich beim ersten Aufruf von GetSupportedModes() den Aufruf des A::~A() Destruktors (!!!???) 😕

    Zusatzinfos:

    Die module bi_a.h und call.cpp stammen aus einer statischen Lib.
    module a.h und a.cpp sind eine eiegene C++ Anwendung die zur statischen Lib gelinkt wird.

    vielleicht jemand da, der so ein konstrukt (wie oben) schonmal gesehen und probleme dazu kennt !?

    vielen dank vorab.



  • BI_A hat keinen virtuellen Destruktor, hinter check fehlt ein Gleichheitszeichen und ich sehe kein Singleton.

    Achja, wenn Get_A_Instance einen Zeiger auf BI_a zurückgibt, ist die Funktion ziemlich schlecht benannt.

    Am besten zeigst du etwas mehr Code.



  • wie ich bereits sagte, ist dies (sehr) vereinfachter code, daher auch der syntaxfehler bei check. der virtuelle destruktor fehlt allerdings auch im original-code (der sich fehlerlos uebersetzen laesst) [muss es den geben ?].

    das mit dem singleton kann meiner meinung nach ignoriert werden und stattdessen eine globale instanz der Klasse A angenommen werden, die beim programm-start in main(..) erzeugt wird.

    ich weiss dass das alles vom programmiercode her vielleicht nicht ausreichend infos bereitsstellt, hatte aber gehofft es wuerde sich vielleicht um ein einfaches prob. handeln, was ich gerade uebersehe.

    den gesamten orig.-code zu posten waere nicht angebracht.

    falls keiner ne idee hierzu hat, auch gut.



  • pepe75 schrieb:

    wie ich bereits sagte, ist dies (sehr) vereinfachter code, daher auch der syntaxfehler bei check. der virtuelle destruktor fehlt allerdings auch im original-code (der sich fehlerlos uebersetzen laesst) [muss es den geben ?].

    Betrachte folgenden Code:

    A* foo = new A();
    BI_A* bar = foo;
    delete bar;    // ups, hier wird nur der BI_A-Destruktor aufgerufen, weil dieser nicht virtual ist
    

    ich weiss dass das alles vom programmiercode her vielleicht nicht ausreichend infos bereitsstellt, hatte aber gehofft es wuerde sich vielleicht um ein einfaches prob. handeln, was ich gerade uebersehe.

    den gesamten orig.-code zu posten waere nicht angebracht.

    Ein Stückchen mehr wäre vielleicht hilfreich (zumindest die Definitionen von allen Funktionen, die du aufrufst).

    {Edit] Der function call trace könnte vielleicht auch noch was hergeben.



  • pepe75 schrieb:

    den gesamten orig.-code zu posten waere nicht angebracht.

    Siehe Link in meiner Signatur - der ideale Code-Post hier im Forum beinhaltet das jeweilige Problem, ist dabei aber so kurz wie nur möglich und trotzdem möglichst kompilierbar. So, dass man den Code nur per Copy & Paste einem beliebigen Compiler vorsetzen muss und den selben Fehler bekommt.



  • @pumuckl:
    der original source-code stammt aus einer umgebung mit mehreren dutzend modulen.
    das (wirkliche) problem auf ein kleines kompilierbares beispiel runterzubrechen ist hier nicht unbedingt so einfach.

    ich hatte gehofft, dass ideen zum problem in dem von mir gesendeteten (jedoch leider nicht compilierbarem) beispiel vielleicht schon allein durchs lesen gefunden werden könnten.

    scheint hier nicht der fall zu sein, trotzdem danke.



  • pepe75 schrieb:

    das (wirkliche) problem auf ein kleines kompilierbares beispiel runterzubrechen ist hier nicht unbedingt so einfach.

    Naja du hast es ja fast geschafft, hätten ja nurnoch 5 Minuten gefehlt 😉

    ich hatte gehofft, dass ideen zum problem in dem von mir gesendeteten (jedoch leider nicht compilierbarem) beispiel vielleicht schon allein durchs lesen gefunden werden könnten.

    Zwar haben einige hier auf sowas einen ziemlich guten Blick, aber nicht jeder kann "im Kopf compilieren" - Compilierbarer Code ist leichter zu analysieren und macht es einfacher, Tips geben zu können

    scheint hier nicht der fall zu sein, trotzdem danke.

    War der Fall. Siehe die Bemerkugnen zum fehlenden virtuellen Destruktor.



  • @pumuckl:

    War der Fall. Siehe die Bemerkugnen zum fehlenden virtuellen Destruktor.

    ich glaube nicht dass das die eigentlich ursache ist (leider momentan nur ne glaubenssache) ..

    irgendwie scheint die virtual function table bei mir im arsch zu sein (irgend ne art von verpointerung) und es wird aus heiterem Himmel ein destruktor aufgerufen

    wie gesagt, trotzdem vielen dank.



  • pepe75 schrieb:

    irgendwie scheint die virtual function table bei mir im ***** zu sein (irgend ne art von verpointerung) und es wird aus heiterem Himmel ein destruktor aufgerufen

    Die vtable zerballern kann man sich folgendermaßen:

    1. Du schreibst eine Klasse V mit n virtuellen Funktionen und kompilierst ihre .cpp. In der .cpp hat die Klasse dann eine vtable der Länge n
    2. Du schiebst im Header eine virtuelle Funktion irgendwo dazwischen und kompilierst einen der Klienten neu, nicht aber die .cpp der Klasse. Der Klient bestimmt für die V-Objekte die Offsets in der vtable anders, als die vtable im Konstruktor von V angelegt wird.
    3. unter bestimmten Umständen linkt das Ganze trotzdem (z.B. bei DLLs) und die Klienten greifen daneben, weil die ermittelten offsets nicht mehr mit den tatsächlichen übereinstimmen.

Anmelden zum Antworten