Programm stürzt nur beim Release-Build ab - wie debuggen?

95

Ich habe hier ein Problem vom Typ "Schroedinger's Cat" - mein Programm (eigentlich die Testsuite für mein Programm, aber dennoch ein Programm) stürzt ab, aber nur, wenn es im Release-Modus erstellt wurde und nur, wenn es über die Befehlszeile gestartet wird . Durch das Debuggen von Höhlenmenschen (dh böse printf () - Nachrichten überall) habe ich die Testmethode ermittelt, bei der der Code abstürzt, obwohl der tatsächliche Absturz leider in einem Destruktor zu passieren scheint, da sich die letzten Trace-Nachrichten befinden, die ich sehe andere Destruktoren, die sauber ausgeführt werden.

Wenn ich versuche, dieses Programm in Visual Studio auszuführen, stürzt es nicht ab. Gleiches gilt beim Starten von WinDbg.exe. Der Absturz tritt nur beim Starten über die Befehlszeile auf. Dies geschieht übrigens unter Windows Vista, und leider habe ich momentan keinen Zugriff auf einen XP-Computer, auf dem ich testen kann.

Es wäre wirklich schön, wenn ich Windows dazu bringen könnte, einen Stack-Trace auszudrucken, oder etwas anderes, als das Programm einfach so zu beenden, als ob es sauber beendet worden wäre. Hat jemand einen Rat, wie ich hier aussagekräftigere Informationen erhalten und hoffentlich diesen Fehler beheben kann?

Bearbeiten: Das Problem wurde in der Tat durch ein außerhalb der Grenzen liegendes Array verursacht, das ich in diesem Beitrag ausführlicher beschreibe . Vielen Dank an alle für Ihre Hilfe bei der Suche nach diesem Problem!

Nik Reiman
quelle
Können Sie eine Probe dieser Testmethode geben?
Akalenuk
Nein, tut mir leid, der Code ist viel zu komplex, um ihn hier einfach einzufügen, und wie ich bereits erwähnt habe, geschieht er nicht in der Testmethode selbst, sondern in einem Destruktor danach. Bei dieser Methode gibt es jedoch keine nicht initialisierten Zeiger oder ähnliches.
Nik Reiman
3
Die meisten Antworten sind kaum mehr als Vermutungen. Es gibt einige gängige Techniken, um abstürzende Release-Builds zu analysieren, ohne einen Debugger anzuhängen
Sebastian
Vielleicht ist es nicht deine Schuld: Ist Optimierungsstufe -O3 in g ++ gefährlich?
Brent Bradburn

Antworten:

127

In 100% der Fälle, von denen ich gesehen oder gehört habe, dass ein C- oder C ++ - Programm im Debugger einwandfrei ausgeführt wird, bei Ausführung im Freien jedoch fehlschlägt, wurde die Ursache über das Ende eines lokalen Funktionsarrays hinaus geschrieben. (Der Debugger legt mehr auf den Stapel, sodass Sie weniger wahrscheinlich etwas Wichtiges überschreiben.)

James Curran
quelle
31
Jemand gibt diesem Mann eine Zigarre! In meinem Fall habe ich einen StringBuilder übergeben, der nicht groß genug für eine P / Invoke-Funktion war. Ich denke, es ist, als würde jemand im Schlaf mit einem magischen Marker auf Ihr Gesicht schreiben: Unter dem Debugger kritzeln sie auf Ihre Stirn, sodass Sie es nicht bemerken, aber ohne den Debugger stechen sie Sie in den Auge ... so etwas. Danke für diesen Tipp!
Nicholas Piasecki
1
In meinem Fall stellte sich heraus, dass es sich bei einem ARM-Prozessor mit Obj-C um ein Ausrichtungsproblem handelte.
Almo
1
11 Jahre später und das klingt immer noch richtig ... vergessen Sie nicht, Ihre Vektoren zu reservieren.
David Tran
1
ok, wie ändert man dann das Verhalten des Debug-Modus, so dass man tatsächlich debuggen kann?
Paul Childs
1
"Jetzt wissen, wo Sie suchen müssen", aber wie sagt Ihnen alles, was beim Debuggen funktioniert, wo das Problem liegt. Obwohl ich denke, dass Ihre Antwort in den meisten Fällen richtig ist und es ein guter Anfang ist, zu wissen, wonach Sie suchen müssen, kann es unerschwinglich teuer sein, eine große Codebasis zu durchsuchen, um genau zu bestimmen, wo das Problem liegt.
Paul Childs
54

Wenn ich zuvor auf solche Probleme gestoßen bin, war dies im Allgemeinen auf die Initialisierung von Variablen zurückzuführen. Im Debug-Modus werden Variablen und Zeiger automatisch auf Null initialisiert, im Release-Modus jedoch nicht. Daher, wenn Sie Code wie diesen haben

int* p;
....
if (p == 0) { // do stuff }

Im Debug-Modus enthält der Code im if nicht ausgeführt, aber im Release-Modus p enthält einen undefinierten Wert, der wahrscheinlich nicht 0 ist, sodass der Code häufig ausgeführt wird und einen Absturz verursacht.

Ich würde Ihren Code auf nicht initialisierte Variablen überprüfen. Dies kann auch für den Inhalt von Arrays gelten.

David Dibben
quelle
In typischen Fällen wird vergessen, eine Elementvariable in (eine) der Initialisierungsliste für Konstruktormitglieder aufzunehmen. Hat den gleichen Effekt, ist jedoch schwieriger zu finden, wenn Sie nicht wissen, dass Sie auch nach einer ordnungsgemäßen Elementinitialisierung suchen sollten.
steffenj
1
Im Debug-Modus werden die Variablen normalerweise mit einer vom Compiler definierten Konstante initialisiert, die beim Debuggen verwendet werden kann, um anzugeben, in welchem ​​Status sich die Variable befindet. Beispiel: Zeiger NULL oder 0xDeadBeef sind beliebt.
Martin York
Debug-Laufzeiten initialisieren den Speicher normalerweise auf einen Wert ungleich Null, insbesondere so, dass NULL-Zeigertests dazu führen, dass der Code so wirkt, als wäre der Zeiger nicht NULL. Andernfalls haben Sie Code, der im Debug-Modus korrekt ausgeführt wird und den Release-Modus zum Absturz bringt.
Michael Burr
1
Nein, die Variablen werden überhaupt nicht initialisiert und es ist immer noch UB, sie zu "verwenden", bis sie zugewiesen sind. Der zugrunde liegende Speicherinhalt wird jedoch häufig mit 0x0000000 oder 0xDEADBEEF oder anderen erkennbaren Mustern vorgefüllt.
Leichtigkeitsrennen im Orbit
26

Bisher hat keine Antwort versucht, einen ernsthaften Überblick über die verfügbaren Techniken zum Debuggen von Release-Anwendungen zu geben:

  1. Release- und Debug-Builds verhalten sich aus vielen Gründen unterschiedlich. Hier ist eine hervorragende Übersicht. Jeder dieser Unterschiede kann einen Fehler im Release-Build verursachen, der im Debug-Build nicht vorhanden ist.

  2. Das Vorhandensein eines Debuggers kann auch das Verhalten eines Programms ändern , sowohl für Release- als auch für Debug-Builds. Siehe diese Antwort. Kurz gesagt, zumindest der Visual Studio-Debugger verwendet den Debug-Heap automatisch, wenn er an ein Programm angehängt wird. Sie können den Debug-Heap mithilfe der Umgebungsvariablen _NO_DEBUG_HEAP deaktivieren. Sie können dies entweder in Ihren Computereigenschaften oder in den Projekteinstellungen in Visual Studio angeben. Dies könnte den Absturz mit dem angeschlossenen Debugger reproduzierbar machen.

    Mehr zum Debuggen von Heap-Korruption hier.

  3. Wenn die vorherige Lösung nicht funktioniert, müssen Sie die nicht behandelte Ausnahme abfangen und einen Post-Mortem-Debugger anhängen , wenn der Absturz auftritt. Sie können hierfür zB WinDbg, Details zu den verfügbaren Post-Mortem-Debuggern und deren Installation bei MSDN verwenden

  4. Sie können Ihren Code für die Ausnahmebehandlung verbessern. Wenn es sich um eine Produktionsanwendung handelt, sollten Sie:

    ein. Installieren Sie einen benutzerdefinierten Terminierungshandler mitstd::set_terminate

    Wenn Sie dieses Problem lokal debuggen möchten, können Sie eine Endlosschleife im Terminierungshandler ausführen und Text an die Konsole ausgeben, um Sie std::terminateüber den Aufruf zu informieren . Schließen Sie dann den Debugger an und überprüfen Sie den Aufrufstapel. Oder Sie drucken den Stack-Trace wie in dieser Antwort beschrieben.

    In einer Produktionsanwendung möchten Sie möglicherweise einen Fehlerbericht nach Hause senden, idealerweise zusammen mit einem kleinen Speicherauszug, mit dem Sie das hier beschriebene Problem analysieren können.

    b. Verwenden Sie den strukturierten Ausnahmebehandlungsmechanismus von Microsoft , mit dem Sie sowohl Hardware- als auch Software-Ausnahmen abfangen können. Siehe MSDN . Sie können Teile Ihres Codes mit SEH schützen und den gleichen Ansatz wie in a) verwenden, um das Problem zu debuggen. SEH enthält weitere Informationen zu der aufgetretenen Ausnahme, die Sie beim Senden eines Fehlerberichts über eine Produktions-App verwenden können.

Sebastian
quelle
16

Dinge, auf die Sie achten sollten:

Array-Überläufe - Der Visual Studio-Debugger fügt Polster ein, die Abstürze stoppen können.

Race-Bedingungen - Sind mehrere Threads beteiligt, wenn dies der Fall ist? Viele Race-Bedingungen werden nur angezeigt, wenn eine Anwendung direkt ausgeführt wird.

Verknüpfen - Ist Ihr Release-Build, der die richtigen Bibliotheken abruft?

Dinge zu versuchen:

Minidump - sehr einfach zu bedienen (einfach in msdn nachschlagen) gibt Ihnen einen vollständigen Crash-Dump für jeden Thread. Sie laden die Ausgabe einfach in Visual Studio und es ist, als würden Sie zum Zeitpunkt des Absturzes debuggen.

morechilli
quelle
1
Hallo, ich habe anonym über diese Antwort abgestimmt. Ich würde gerne verstehen warum?
Morechilli
12

Sie können WinDbg als Ihren Postmortem-Debugger festlegen. Dadurch wird der Debugger gestartet und beim Absturz an den Prozess angehängt. Verwenden Sie die Option / I, um WinDbg für das Postmortem-Debugging zu installieren (beachten Sie, dass es groß geschrieben wird ):

windbg /I

Weitere Details hier .

Was die Ursache betrifft, handelt es sich höchstwahrscheinlich um eine einheitliche Variable, wie die anderen Antworten vermuten lassen.

Franci Penov
quelle
2
Und vergessen Sie nicht, dass der Compiler PDB-Dateien auch für Release-Builds generieren kann, obwohl dies nicht die Standardeinstellung ist.
Michael Burr
Die einzig wahre Antwort auf die Frage wirklich.
Sebastian
10

Nach vielen Stunden des Debuggens fand ich schließlich die Ursache des Problems, das tatsächlich durch einen Pufferüberlauf verursacht wurde und einen einzelnen Byte-Unterschied verursachte:

char *end = static_cast<char*>(attr->data) + attr->dataSize;

Dies ist ein Zaunpfostenfehler (Off-by-One-Fehler) und wurde behoben durch:

char *end = static_cast<char*>(attr->data) + attr->dataSize - 1;

Das Seltsame war, dass ich _CrtCheckMemory () mehrmals um verschiedene Teile meines Codes aufgerufen habe und sie immer 1 zurückgegeben haben. Ich konnte die Ursache des Problems finden, indem ich "return false" platzierte. ruft im Testfall auf und ermittelt schließlich durch Ausprobieren, wo der Fehler lag.

Vielen Dank an alle für Ihre Kommentare - ich habe heute viel über windbg.exe gelernt! :) :)

Nik Reiman
quelle
8
Heute habe ich ein ähnliches Problem debuggt und _CrtCheckMemory () gab immer 1 zurück. Aber dann wurde mir klar, warum: Im Release-Modus ist _CrtCheckMemory # definiert als ((int) 1).
Brian Morearty
7

Auch wenn Sie Ihre Exe als Release-Version erstellt haben, können Sie dennoch PDB-Dateien (Program Database) generieren, mit denen Sie Trace verfolgen und eine begrenzte Anzahl von Variablenprüfungen durchführen können. In Ihren Build-Einstellungen gibt es eine Option zum Erstellen der PDB-Dateien. Schalten Sie dies ein und verknüpfen Sie es erneut. Versuchen Sie dann zuerst, von der IDE aus zu laufen, um festzustellen, ob der Absturz auftritt. Wenn ja, dann großartig - Sie sind bereit, sich die Dinge anzuschauen. Wenn nicht, können Sie beim Ausführen über die Befehlszeile eines von zwei Dingen tun:

  1. Führen Sie EXE aus und führen Sie vor dem Absturz einen Attach To Process aus (Menü Extras in Visual Studio).
  2. Wählen Sie nach dem Absturz die Option zum Starten des Debuggers aus.

Wenn Sie aufgefordert werden, auf PDB-Dateien zu verweisen, suchen Sie nach diesen. Wenn die PDBs im selben Ausgabeordner wie Ihre EXE- oder DLL-Dateien abgelegt wurden, werden sie wahrscheinlich automatisch abgerufen.

Die PDBs bieten einen Link zur Quelle mit genügend Symbolinformationen, damit Stapelspuren, Variablen usw. angezeigt werden können. Sie können die Werte wie gewohnt überprüfen. Beachten Sie jedoch, dass Sie falsche Messwerte erhalten können, da der Optimierungsdurchlauf möglicherweise nur die Bedeutung hat erscheinen in Registern oder Dinge passieren in einer anderen Reihenfolge als Sie erwarten.

NB: Ich gehe hier von einer Windows / Visual Studio-Umgebung aus.

Greg Whitfield
quelle
3

Abstürze wie diese werden fast immer verursacht, weil eine IDE normalerweise den Inhalt einer nicht initialisierten Variablen auf Nullen, Null oder einen anderen solchen "vernünftigen" Wert setzt, während Sie bei nativer Ausführung den zufälligen Müll erhalten, den das System aufnimmt.

Ihr Fehler ist daher mit ziemlicher Sicherheit, dass Sie so etwas wie einen Zeiger verwenden, bevor er ordnungsgemäß initialisiert wurde, und dass Sie damit in der IDE davonkommen, weil er nirgendwo gefährlich zeigt - oder der Wert von Ihnen verarbeitet wird Fehlerprüfung - aber im Release-Modus macht es etwas Böses.

Cruachan
quelle
3

Um einen Absturzspeicherauszug zu erhalten, den Sie analysieren können:

  1. Generieren Sie PDF-Dateien für Ihren Code.
  2. Sie müssen Ihre exe und dlls unter derselben Adresse laden.
  3. Aktivieren Sie den Post-Mortem-Debugger wie z Dr. Watson
  4. Überprüfen Sie die Adresse für Absturzfehler mit einem Tool wie dem Crashfinder .

Sie sollten auch die Tools unter Debugging-Tools für Windows überprüfen . Sie können die Anwendung überwachen und alle Ausnahmen der ersten Chance anzeigen, die vor Ihrer Ausnahme der zweiten Chance aufgetreten sind.

Ich hoffe es hilft...

Yuval Peled
quelle
3

Eine gute Möglichkeit, einen solchen Fehler zu debuggen, besteht darin, Optimierungen für Ihren Debug-Build zu aktivieren.

Mgill404
quelle
2

Einmal hatte ich ein Problem, als sich die App ähnlich wie deine verhielt. Es stellte sich heraus, dass es sich bei Sprintf um einen unangenehmen Pufferüberlauf handelte. Natürlich funktionierte es, wenn ein Debugger angeschlossen war. Was ich getan habe, war, einen nicht behandelten Ausnahmefilter zu installieren ( SetUnhandledExceptionFilter) installiert ) in dem ich einfach unendlich blockiert habe (mit WaitForSingleObject auf einem falschen Handle mit dem Timeout-Wert INFINITE).

Sie könnten also etwas in der Art von:

long __stdcall MyFilter (EXCEPTION_POINTERS *)
{
    HANDLE hEvt = :: CreateEventW (0,1,0,0);
    if (hEvt)
    {
        if (WAIT_FAILED == :: WaitForSingleObject (hEvt, INFINITE))
        {
            // Protokollfehler
        }}
    }}

}}
// irgendwo in deinem wmain / WinMain:
SetUnhandledExceptionFilter (MyFilter);

Ich habe dann den Debugger angehängt, nachdem sich der Fehler manifestiert hatte (das GUI-Programm reagiert nicht mehr).

Dann können Sie entweder einen Dump nehmen und später damit arbeiten:

.dump / ma path_to_dump_file

Oder debuggen Sie es sofort. Der einfachste Weg besteht darin, zu verfolgen, wo der Prozessorkontext von der Laufzeit-Ausnahmebehandlungsmaschine gespeichert wurde:

sd esp Range 1003f

Der Befehl durchsucht den Adressraum des Stapels nach CONTEXT-Datensätzen, sofern die Suchdauer eingehalten wird. Normalerweise benutze ich so etwas wie 'l? 10000' . Beachten Sie, dass Sie keine ungewöhnlich großen Zahlen als Datensatz verwenden, nach dem Sie normalerweise in der Nähe des nicht übergebenen Ausnahmefilterrahmens suchen. 1003f ist die Kombination von Flags (ich glaube, sie entspricht CONTEXT_FULL), die zum Erfassen des Prozessorstatus verwendet wird. Ihre Suche würde ungefähr so ​​aussehen:

0: 000> sd esp l1000 1003f
0012c160 0001003f 00000000 00000000 00000000? ...............

Wenn Sie die Ergebnisse zurückerhalten, verwenden Sie die Adresse im Befehl cxr:

.cxr 0012c160

Dies bringt Sie genau zum Zeitpunkt des Absturzes zu diesem neuen KONTEXT (Sie erhalten genau den Stack-Trace zum Zeitpunkt des Absturzes Ihrer App). Verwenden Sie außerdem:

.exr -1

um genau herauszufinden, welche Ausnahme aufgetreten war.

Ich hoffe es hilft.

deemok
quelle
2

Manchmal geschieht dies, weil Sie wichtige Operationen in das Makro "assert" eingewickelt haben. Wie Sie vielleicht wissen, wertet "assert" Ausdrücke nur im Debug-Modus aus.

Mohamad mehdi Kharatizadeh
quelle
1

Haben Sie im Hinblick auf Ihre Probleme beim Abrufen von Diagnoseinformationen versucht, adplus.vbs als Alternative zu WinDbg.exe zu verwenden? Verwenden Sie zum Anhängen an einen laufenden Prozess

adplus.vbs -crash -p <process_id>

Oder um die Anwendung zu starten, falls der Absturz schnell passiert:

adplus.vbs -crash -sc your_app.exe

Ausführliche Informationen zu adplus.vbs finden Sie unter: http://support.microsoft.com/kb/286350

DocMax
quelle
1

Ntdll.dll mit angehängtem Debugger

Ein wenig bekannter Unterschied zwischen dem Starten eines Programms von der IDE oder WinDbg im Gegensatz zum Starten von einem Befehl über die Befehlszeile / den Desktop besteht darin, dass ntdll.dll beim Starten mit einem angeschlossenen Debugger (dh IDE oder WinDbg) eine andere Heap-Implementierung verwendet, die eine kleine Validierung durchführt auf die Speicherzuordnung / Freigabe.

Sie können einige relevante Informationen im unerwarteten Benutzer-Haltepunkt in ntdll.dll lesen . Ein Tool, mit dem Sie das Problem möglicherweise identifizieren können, ist PageHeap.exe .

Crash-Analyse

Sie haben nicht geschrieben, was der "Absturz" ist, den Sie erleben. Sobald das Programm abstürzt und Ihnen anbietet, die Fehlerinformationen an Microsoft zu senden, sollten Sie in der Lage sein, auf die technischen Informationen zu klicken und zumindest den Ausnahmecode zu überprüfen. Mit etwas Aufwand können Sie sogar eine Post-Mortem-Analyse durchführen (siehe Heisenbug) : WinApi Programm stürzt auf einigen Computern) für weitere Anweisungen)

Suma
quelle
1

Vista SP1 hat tatsächlich einen wirklich schönen Crash-Dump-Generator im System eingebaut. Leider ist es nicht standardmäßig aktiviert!

Siehe diesen Artikel: http://msdn.microsoft.com/en-us/library/bb787181(VS.85).aspx

Der Vorteil dieses Ansatzes besteht darin, dass keine zusätzliche Software auf dem betroffenen System installiert werden muss. Griff es und zerreiß es, Baby!


quelle
1

Nach meiner Erfahrung handelt es sich dabei hauptsächlich um Probleme mit der Speicherbeschädigung.

Zum Beispiel :

char a[8];
memset(&a[0], 0, 16);

: /*use array a doing some thing */

Es ist sehr gut möglich, im Debug-Modus normal zu sein, wenn man den Code ausführt.

Aber in der Veröffentlichung wäre / könnte das ein Absturz sein.

Für mich ist es zu mühsam, dort zu stöbern, wo die Erinnerung nicht gebunden ist.

Verwenden Sie einige Tools wie Visual Leak Detector (Windows) oder Valgrind (Linux).

Gaiger Chen
quelle
1

Ich habe viele richtige Antworten gesehen. Es gibt jedoch keine, die mir geholfen haben. In meinem Fall wurden die SSE-Anweisungen mit dem nicht ausgerichteten Speicher falsch verwendet . Sehen Sie sich Ihre Mathematikbibliothek an (falls Sie eine verwenden) und versuchen Sie, die SIMD-Unterstützung zu deaktivieren, den Absturz neu zu kompilieren und zu reproduzieren.

Beispiel:

Ein Projekt enthält mathfu und verwendet die Klassen mit dem STL-Vektor: std :: vector <mathfu :: vec2> . Eine solche Verwendung wird wahrscheinlich zum Zeitpunkt der Erstellung des Elements mathfu :: vec2 zum Absturz führen , da der STL-Standardzuweiser die erforderliche 16-Byte-Ausrichtung nicht garantiert. In diesem Fall kann man, um die Idee zu beweisen, #define MATHFU_COMPILE_WITHOUT_SIMD_SUPPORT 1vor jedem Include der mathfu definieren , in der Release-Konfiguration neu kompilieren und erneut prüfen.

Die Debug und RelWithDebInfo Konfigurationen funktionierten gut für mein Projekt, aber nicht die Veröffentlichung ein. Der Grund für dieses Verhalten liegt wahrscheinlich darin, dass der Debugger Zuordnungs- / Freigabeanforderungen verarbeitet und eine Speicherbuchhaltung durchführt, um die Zugriffe auf den Speicher zu überprüfen und zu verifizieren.

Ich habe die Situation in Visual Studio 2015- und 2017-Umgebungen erlebt.

Vlad Serhiienko
quelle
0

Ähnliches passierte mir einmal mit GCC. Es stellte sich als zu aggressive Optimierung heraus, die nur beim Erstellen der endgültigen Version und nicht während des Entwicklungsprozesses aktiviert wurde.

Um die Wahrheit zu sagen, war es meine Schuld, nicht die von gcc, da ich nicht bemerkte, dass mein Code auf der Tatsache beruhte, dass diese bestimmte Optimierung nicht durchgeführt worden wäre.

Ich habe viel Zeit gebraucht, um es aufzuspüren, und bin nur dazu gekommen, weil ich in einer Newsgroup gefragt habe und jemand mich dazu gebracht hat, darüber nachzudenken. Lassen Sie mich den Gefallen erwidern, falls dies auch Ihnen passiert.

Remo.D
quelle
0

Ich fand diesen Artikel nützlich für Ihr Szenario. ISTR die Compiler-Optionen waren etwas veraltet. Schauen Sie sich in Ihren Visual Studio-Projektoptionen um, um zu sehen, wie Sie PDF-Dateien für Ihren Release-Build usw. generieren.

Sprudler
quelle
0

Es ist verdächtig, dass es außerhalb des Debuggers und nicht innerhalb des Debuggers passieren würde. Das Ausführen im Debugger ändert normalerweise nicht das Anwendungsverhalten. Ich würde die Umgebungsunterschiede zwischen der Konsole und der IDE überprüfen. Kompilieren Sie die Version natürlich auch ohne Optimierungen und mit Debug-Informationen und prüfen Sie, ob sich dies auf das Verhalten auswirkt. Schauen Sie sich zum Schluss die Post-Mortem-Debugging-Tools an, die andere Leute hier vorgeschlagen haben. Normalerweise können Sie einen Hinweis von ihnen erhalten.

Nick
quelle
0

Das Debuggen von Release-Builds kann aufgrund von Optimierungen, die die Reihenfolge ändern, in der Zeilen Ihres Codes ausgeführt zu werden scheinen, schmerzhaft sein. Es kann wirklich verwirrend werden!

Eine Technik, um das Problem zumindest einzugrenzen, besteht darin, MessageBox () zu verwenden, um schnelle Anweisungen anzuzeigen, die angeben, zu welchem ​​Teil des Programms Ihr Code gehören muss ("Starting Foo ()", "Starting Foo2 ()"). Setzen Sie sie an die Spitze der Funktionen im Bereich Ihres Codes, den Sie vermuten (was haben Sie zu dem Zeitpunkt getan, als er abstürzte?). Wenn Sie feststellen können, welche Funktion verwendet wird, ändern Sie die Meldungsfelder in Codeblöcke oder sogar in einzelne Zeilen innerhalb dieser Funktion, bis Sie sie auf einige Zeilen eingrenzen. Anschließend können Sie den Wert der Variablen ausdrucken, um festzustellen, in welchem ​​Zustand sie sich zum Zeitpunkt des Absturzes befinden.


quelle
Er hat bereits versucht, mit printfs zu bestreuen, damit Nachrichtenboxen nichts Neues auf die Party bringen.
Greg Whitfield
0

Versuchen Sie, _CrtCheckMemory () zu verwenden, um festzustellen, in welchem ​​Status sich der zugewiesene Speicher befindet. Wenn alles gut geht, _CrtCheckMemory liefert TRUE , sonst FALSE .

Vhaerun
quelle
0

Sie können Ihre Software mit aktivierten globalen Flags ausführen (siehe Debugging-Tools für Windows). Es wird sehr oft helfen, das Problem zu lösen.

Marcin Gil
quelle
0

Lassen Sie Ihr Programm einen Mini-Dump generieren, wenn die Ausnahme auftritt, und öffnen Sie ihn dann in einem Debugger (z. B. in WinDbg). Die wichtigsten Funktionen: MiniDumpWriteDump, SetUnhandledExceptionFilter

mikhailitsky
quelle
0

Hier ist ein Fall, den ich hatte, den jemand als lehrreich empfinden könnte. Es stürzte nur bei der Veröffentlichung in Qt Creator ab - nicht beim Debuggen. Ich habe INI-Dateien verwendet (da ich Apps bevorzuge, die auf andere Laufwerke kopiert werden können, im Vergleich zu Apps, die ihre Einstellungen verlieren, wenn die Registrierung beschädigt wird). Dies gilt für alle Apps, deren Einstellungen im Verzeichnisbaum der Apps gespeichert sind. Wenn sich die Debug- und Release-Builds in verschiedenen Verzeichnissen befinden, können Sie auch eine andere Einstellung festlegen. Ich hatte eine Präferenz eingecheckt, die in der anderen nicht eingecheckt war. Es stellte sich heraus, dass dies die Quelle meines Absturzes war. Gut, dass ich es gefunden habe.

Ich hasse es, es zu sagen, aber ich habe den Absturz nur in MS Visual Studio Community Edition diagnostiziert. Nachdem Sie VS installiert haben, lassen Sie meine App in Qt Creator abstürzen und öffnen Sie sie im Debugger von Visual Studio . Während meine Qt-App keine Symbolinformationen hatte, stellte sich heraus, dass die Qt-Bibliotheken einige hatten. Es führte mich zur beleidigenden Linie; da konnte ich sehen, welche Methode aufgerufen wurde. (Dennoch denke ich, dass Qt ein praktisches, leistungsstarkes und plattformübergreifendes LGPL-Framework ist.)

CodeLurker
quelle
-3

Ich hatte diesen Fehler und vs stürzte sogar beim Versuch! Reinigen! Mein Projekt. Also habe ich die obj-Dateien manuell aus dem Release-Verzeichnis gelöscht und danach hat es gut funktioniert.

Chris89
quelle
-6

Ich stimme Rolf zu. Da die Reproduzierbarkeit so wichtig ist, sollten Sie keinen Nicht-Debug-Modus verwenden. Alle Ihre Builds sollten debuggbar sein. Wenn Sie zwei Ziele zum Debuggen haben, verdoppelt sich Ihre Debugging-Last mehr als. Versenden Sie einfach die "Debug-Modus" -Version, es sei denn, sie ist unbrauchbar. In diesem Fall machen Sie es verwendbar.

wnoise
quelle
Dies kann für 10% der Anwendungen funktionieren, aber sicherlich nicht für alle. Möchten Sie Spiele spielen, die als DEBUG-Builds veröffentlicht wurden? Verschenken Sie Ihren geschützten geheimen Sicherheitscode im zerlegungsfreundlichen Modus, vielleicht sogar zusammen mit den PDBs? Ich denke nicht.
steffenj
Steffenj: Ich möchte, dass Spieleentwickler Fehler finden. Idealerweise, bevor sie versendet werden, aber wenn es danach ist, möchte ich, dass sie genug Informationen erhalten, um sie zu reproduzieren und aufzuspüren. Wenn es sich um einen Geheimcode handelt, gilt die Marke nicht. PDBs? Proteindatenbank? Python-Debugger?
wnoise
IMHO, das ist eine schlechte Idee. Die ausführbaren Dateien sind größer, nicht optimiert und laufen viel langsamer. Diese Fälle sind wirklich ziemlich selten; obwohl besonders verrückt, wenn sie passieren. Sie sollten kein durchweg minderwertiges Produkt liefern, da Sie sich Sorgen über das äußerst seltene Debugging im schlimmsten Fall machen. (Meins war nicht eine der vielen Abstimmungen.) Ich habe für die NASA programmiert. und wir sagten, dass mindestens jede Codezeile einmal getestet werden sollte. Unit-Tests können ebenfalls hilfreich sein.
CodeLurker