Wie debugge ich ein schwer zu reproduzieren Absturz mit keine brauchbaren call-stack?
Bin ich die Begegnung mit einer ungeraden Absturz in unserer software und ich habe eine Menge ärger Debuggen, und so bin ich sucht ALSO Rat, wie man es angehen.
Den Absturz ist eine Zugriffsverletzung beim Lesen einer NULL-Zeiger:
Erste-chance-Ausnahme bei $00CF0041.
Exception-Klasse $C0000005 mit der Meldung
'access violation bei 0x00cf0041: Lesen
der Adresse 0 x 00000000".
Passiert es nur 'manchmal' - ich habe es nicht geschafft, herauszufinden, jedem Reim oder Grund, noch, wenn - und nur in den Haupt-thread. Wenn es Auftritt, wird der call-stack enthält eine falsche Angabe:
Für den Haupt-thread, was es ist, es sollte zeigen, ein großer Stapel voller andere Elemente.
Zu diesem Zeitpunkt alle anderen threads inaktiv sind (meist sitzen in WaitForSingleObject
oder eine ähnliche Funktion.) Ich habe nur gesehen, dieser Absturz auftreten, in den Haupt-thread. Es hat immer die gleichen call-stack einen Eintrag, in derselben Methode, an derselben Adresse. Diese Methode kann oder kann nicht bezogen werden - wir verwenden die VCL in unserer Anwendung. Meine Wette ist, dass etwas, das (möglicherweise schon eine ganze Weile her) korrumpiert den stack, und die Adresse, wo es abstürzt, ist tatsächlich zufällig. Hinweis: es wurde die gleiche Adresse für verschiedene builds, obwohl - es ist wahrscheinlich nicht wirklich zufällig.
Hier ist, was ich versucht habe:
- Versuchen, um es zu reproduzieren zuverlässig an einem bestimmten Punkt. Ich habe nichts gefunden, was reproduziert es jedes mal, und ein paar Sachen gelegentlich tun, oder nicht tun, ohne ersichtlichen Grund. Diese sind nicht " eng " genug Aktionen, um einzugrenzen, um einen bestimmten Abschnitt des Codes. Es kann sein timing verwandt, aber an der Stelle, die IDE-Pausen, andere threads sind in der Regel nichts zu tun. Ich kann nicht ausschließen, ein threading-problem, aber denke, es ist unwahrscheinlich.
- Gebäude mit zusätzlichen debugging-Anweisungen (zusätzliche debug-Informationen, extra-fest, etc.) Nach tun, der Absturz tritt nie ein.
- Gebäude mit Codeguard aktiviert. Nach tun, der Absturz tritt nie ein und Codeguard zeigt keine Fehler.
Meine Fragen:
1. Wie finde ich welchen code die den Absturz verursacht? Wie mache ich das äquivalent zu Fuß zurück bis der stack?
2. Welche Allgemeinen Tipps haben Sie für, wie auf die Spur, die Ursache für diesen Absturz?
Ich bin mit Embarcadero RAD Studio 2010 (das Projekt beinhaltet hauptsächlich C++ Builder-code und kleine Mengen von Delphi.)
Edit: ich dachte, ich sollte hinzufügen, was tatsächlich verursacht diese. Es war ein thread, der genannt ReadDirectoryChangesW
und dann, mit GetOverlappedResult
, wartete auf ein Ereignis, um fortzufahren und etwas zu tun mit den änderungen. Die Veranstaltung wurde auch signalisiert, um zu beenden, den Faden nach Einstellung ein status-flag. Das problem war, dass, wenn der thread beendet wird es nie aufgerufen CancelIO
. Als ein Ergebnis, Windows war noch die Verfolgung von änderungen und wahrscheinlich noch schriftlich an den Puffer, wenn das Verzeichnis geändert, obwohl der Puffer, overlapped-Struktur und Ereignis gab es nicht mehr (auch nicht der thread-Kontext, in dem Sie erstellt wurden.) Wenn CancelIO
genannt wurde, gab es keine weiteren Abstürze.
- Ich bin nicht vertraut mit CodeGaurd - gilt das auch vorstellen Stapel Kanaren und Validierung? Ich Frage, weil Sie das mischen von C++ und Delphi - was bedeutet, dass Sie möglicherweise mischen Aufrufkonventionen, ohne es zu merken. Das kann sehr schnell zu mess up your stack in einer Weise, die zeigen würde, wie eine scheinbar zufällige Absturz auf deinen main-thread mit einem korrupten call-stack.
- Codeguard füllt den nicht initialisierten Teil des Stapels mit einem byte-Muster. Es auch (versucht) zu überprüfen, Dinge wie der Zugriff auf freigegebenen Speicher, überlauf im Speicher zugewiesen, etc. Immer eine Aufrufkonvention falsch wäre auf jeden Fall etwas bewirken, wie diese, ja (und danke für die Anregung!) aber wenn das so ist ich habe keine Ahnung, wohin: C++ Builder ist konzipiert für die Zusammenarbeit mit Delphi-code, und wir hätten einen Fehler gemacht haben, in einer Erklärung irgendwo, und die meisten sind IDE - oder compiler-verwaltet. Ich denke, die entscheidende Frage ist dann, wie würde ich gehen über die Suche nach einem falsch deklarierten Methode?
- Ich bin nicht setzen dieses als eine Antwort, denn es ist vage, aber möchten Sie vielleicht versuchen Sie einen anderen debugger. Sie geben können, z.B. WinDbg Hinweise (oder alles) zu rekonstruieren und die realen callstack, wenn es beschädigt ist oder verwirrt.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Sogar, wenn die IDE-vorausgesetzt, stack-trace ist nicht sehr vollständig, das bedeutet nicht, dass es nicht noch nützliche Informationen auf dem stack. Öffnen Sie die CPU-Ansicht und überprüfen Sie die stack-Bereich; für alle CALL-Befehl, Rückkehr-Adresse auf den stack geschoben wird. Da der stack wächst nach unten, finden Sie diese Absenderadressen über die aktuelle stack-Position, D. H. durch Blättern nach oben im stack-Bereich.
Den stack für den Haupt-thread wird irgendwo rund $00120000 oder $00180000 (address space randomization in Vista und aufwärts hat es mehr zufällig). Code für das Hauptprogramm wird irgendwo rund $00400000. Sie können spekulativ untersuchen, Elemente auf dem Stapel, die nicht so Aussehen wie integer-Daten (niedrige Werte) oder einen Stapel Adressen ($00120000+ Sortiment) rechts-Klick auf die stack-Eintrags und Auswahl Folgen -> in der Nähe-Code, die bewirkt, dass die Demontage Fenster zu springen-code-Adresse. Wenn es so aussieht ungültigen code, es ist wahrscheinlich nicht ein Gültiger Eintrag in der stack-trace. Wenn es gültig ist der code, es kann sein OS code (Häufig um die $77000000 und oben) in dem Fall, dass Sie nicht haben, aussagekräftige Symbole, aber jeder so oft treffen Sie auf eine tatsächliche richtige stack-Eintrags.
Diese Technik, wenn auch etwas mühsam ist, kann man Sie zu sinnvollen stack trace-info, wenn der debugger nicht in der Lage zu verfolgen die Dinge durch. Es hilft Ihnen nicht, wenn ESP (stack pointer) geschraubt wurde, mit, aber. Zum Glück, das ist ziemlich selten.
Das ist der Grund, warum ich aus den Prozess-Stack-viewer 🙂
http://code.google.com/p/asmprofiler/wiki/ProcessStackViewer
Kann es zeigen Sie den stack mit raw stack-Trace, so zeigt es den kompletten Stapel, wenn die normale stack-Trace nicht möglich ist.
Aber Vorsicht: roh-stack-Trace wird sich zeigen "false-positives"! Jede Adresse auf dem Stapel, für die eine Funktion namens gefunden werden kann, wird aufgeführt.
Es hat mir geholfen, eine Anzahl von Zeiten, wenn ich lief in das gleiche problem wie deins (kein normaler stack zu Fuß von Delphi möglich, da auf ungültige stack-Zustand)
Edit: neue version hochgeladen, auf der website war eine alte version (ich benutze die neue version selber viel)
http://asmprofiler.googlecode.com/files/AsmProfiler_Sampling%20v1.0.7.13.zip
Threading kann der Grund sein hier. Die üblichen verdächtigen sind threads, die ÜBERLAPPENDE Strukturen auf dem stack und threads, zu senden, Zeiger auf Objekte, die auf den Stapel zu den anderen threads.
Kann es möglich sein, sich zu erholen partial stack-Informationen, wenn Sie mit der Deubgging-Tools Für Windows und Einsatz der "dps" - Befehl.
Bin ich mir nicht 100% sicher, aber aus dem Bild, das Sie, sofern ich glaube, dass irgendwo auf der Ausführung, die Sie versuchen, Zugriff auf ein Objekt in eine TList, die NULL ist. also:
In Bezug auf debugging und die Suche nach dem tatsächlichen Ort, wo die Ausnahme ausgelöst wird, ist nie eine leichte Aufgabe, vor allem, wenn es gibt nicht viel Informationen oder es ist schwer zu reproduzieren, in diesem Fall ich in der Regel:
gehen Sie Schritt für Schritt aus dem Hauptformular in der Ausführung(falls keine Ausnahme, bis dort)
beim gehen Schritt für Schritt, wenn ich finden unsichere code-ich habe es zwischen try...except und Bedingungen für Indizes(wenn ich die arrays, Listen, erwartete Werte übergeben werden, etc.)
wenn die oben nicht finden die Frage, ob einige Bibliotheken sind nicht die
verwenden Eureka-log, es manchmal nicht so gut(sehr wenige Male), aber es in der Regel Punkte, die Sie in die richtige Richtung
Ich habe zahlreiche Probleme ähnlich wie bei Ihnen und ich kann Ihnen sagen, dass das Problem war fast wie ein extrem einfach zu beheben, aber wenn der Fehler erscheint, dass ich nicht ein "Punkt in der Nähe" der Fehler.