Absturz wegen virtueller Funktion in embedded XP



  • Ich habe eine Basisklasse geschrieben die eine
    abstrakte und eine virtuelle Funktion enthält.

    Auf meinem Entwicklungsrechner (XP) Visual Studio 2008 (C++)
    läuft die Software.
    Beim Remotedebuggen hatte ich einige Probleme, es klappt nicht.
    Aber mit Logausgaben habe ich herausgefunden das die Software Probleme auf der
    Zielplattform (XPembedded) hat.

    Eine einfache Funktion virtual char * getFilename()
    brachte die Software zum Stillstand als sie von einer Kindklasse aufgerufen wurde.

    Nachdem ich das Virtual entfernt habe lief die Software.
    Kann mir bitte jemand sagen ob virtual grundsätzlich nicht auf embedded funktioniert oder ob es sein kann das ich etwas anderes nicht berücksichtigt habe
    bzw. noch etwas beacht5en muss ?

    Danke



  • Das OS hat nix mit dem erzeugten Code zu tun. Somit muss Dein Probem ein anderes sein...
    Remote-Debugging sollte eigentlich kein Problem sein... stelle halt die Security auf "None"...



  • Kann mir bitte jemand sagen ob virtual grundsätzlich nicht auf embedded funktioniert

    Wie Jochen schon geschrieben hat: nein, daran liegt's nicht.

    oder ob es sein kann das ich etwas anderes nicht berücksichtigt habe

    Klar hast du was übersehen, sonst würde das Programm ja nicht stehen bleiben. Dass es bei dir auf dem Entwicklungsrechner nicht passiert, kann 1000 Gründe haben.
    Dass das Entfernen von virtual den beobachteten Effekt "behebt", kann auch 1000 Gründe haben.

    Vielleicht überschreibt irgendein Programmteil den Vtable-Pointer des Objekts. Oder gar den Vtable selbst. Oder du startest in einem Basisklassen-Konstruktor einen Thread, der dann gleich virtuelle Funktionen der Klasse aufruft. Oder eben 100 andere Sachen.


  • 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