Absturz wegen virtueller Funktion in embedded XP


  • Mod

    Ich kann mich meinen Vorrednern nur anschließen.

    Nur mal ein simples Beispiel.
    Du überschreibst zum Beispiel Speicher und die ersten 4 Bytes eines Objektes werden überschrieen (das ist die vtable). Nun machst Du was mit dem Objekt und einer virtuellen Funktion. Das muss nun krachen, denn die vtable zeigt ins Nirwana.
    Wenn Du nun die Funktion nicht mehr virtuell machst, dann wird der Compiler die Funktion direkt aufrufen und den tis Zeiger benutzen. Da aber nur die ersten Bytes zerstört sind, läuft nun alles normal.

    HTH



  • Hallo,
    danke für die Antworten, ich kann mir auch schwer vorstellen das es daran liegt.
    Andererseits ist das entfernen der virtuals erstmal eine Lösung.
    Werde mich später darum nochmal kümmern.
    Ich wollte Jochens stackwalker einsetzen, leider zeigt der mir in der Releaseversion keine Datei und Funktionsnamen und die Debugversion läuft
    auch noch nicht auf dem Zielsystem.
    Ihr seht einige Baustellen, wie immer wenig Zeit und jetzt muss weils erstmal geht
    an anderen Dingen gearbeitet werden.
    Vielleicht kommt zwischendurch ein Durchbruch. Ich wüsste gern wer bzw. was den vptr zerstört.

    Habt ihr einen Tip wie ich debuggen könnte um herauszufinden wann ich der vptr ändert ?

    <><



  • MBreuer schrieb:

    Ich wollte Jochens stackwalker einsetzen, leider zeigt der mir in der Releaseversion keine Datei und Funktionsnamen und die Debugversion läuft
    auch noch nicht auf dem Zielsystem.

    Der Stackwalker zeigt prinzipiell nur die Infos innvoll an, wenn Du auch die PDB-Datei mitlieferst...

    MBreuer schrieb:

    Habt ihr einen Tip wie ich debuggen könnte um herauszufinden wann ich der vptr ändert ?

    Einfach einen Data-Breakpoint auf den "this"-Zeiger (bzw. deren Adresse) setzen...



  • Ich habe eine Klasse(A) die als Attribut ein Objekt der problematischen Klasse hat.
    Diese Klasse(A) startet einen pThread und übergibt einen this Zeiger.
    Mein Data-Breakpoint hält an und zeigt mir Assembler-Code, den ich leider nicht deuten kann, aber die Tatsache allein ist denke ich schon verdächtig.

    Der Kostruktor der Klasse(A) ist schon abgearbeitet.
    Ich habe das Attribut in der Klasse(A) lediglich deklariert.

    Sollte ich es durch expliziten Konstruktoraufruf in dem Konstruktor der Klasse(A) definieren ?


  • Mod

    Der Assembler Code interessiert nicht. Schau Dir den Callstack an, wer was wann wo aufrufen wollte!



  • void A::startThread(void)
    {
    	pthread_attr_t pthread_custom_attr;
    	pthread_attr_init(&pthread_custom_attr);
    	pthread_create(&thread,&pthread_custom_attr,A::worker,this);
    }
    

    Das Problem ist in der Zeile mit dem this, das sagt mir aber leider nichts.


  • Mod

    Der this Zeiger ist vermutlich ungültig.
    Was sagt der weitere Callstack?



  • Das A-Objekt wird direkt in main erzeugt.
    Dann nach init, wird startThread() aufgerufen ????



  • Ich tippe mal darauf dass A::startThread im Konstruktor von A aufgerufen wird, und A als Basisklasse für B herhalten muss.

    Die A::worker Funktion ruft dann ne virtuelle Funktion auf, Bumm. Falsche Funktion wird aufgerufen, weil das Objekt ja noch garnicht "fertig" ist, und der Vtable Zeiger immernoch auf den Vtable von A zeigt (und nicht auf den von B).

    Klassiker.



  • Fazit: Im *Konstruktor* darf man *nie nicht* virtuelle Methoden aufrufen!!!
    Und schon gar keine Threads starten und den "this" Zeiger übergeben... der Thread läuft sofort los und ruft womöglich virtuelle Methoden auf, die dann wieder zum absturz führen (ist aber ein Timing-Problem, deshalb tritt es vermutlich nicht immer auf).

    Also:
    1. Im Konstruktor wirklich nur Dinge initialisieren!
    2. Eine "start()" Methode machen, die dann den Therad startet



  • Hallo,

    der A-Konstruktor ist abgearbeitet.
    (dann sind doch auch meine deklarierten Attribute initialisiert auch wenn ich nicht explizit im Konstruktor nochmal myClass = MyClass() schreibe oder ?)

    danach kommt die A-init() Funktion
    anschliessend wird A-startThread() aufgerufen.

    Insofern ist denke ich alles ok.


Anmelden zum Antworten