Wie kann man feststellen, wo sich der Fehler im Code befindet, der einen Segmentierungsfehler verursacht ?
Kann mein compiler ( gcc
) den Ort des Fehlers im Programm anzeigen?
c++
c
debugging
segmentation-fault
Trilarion
quelle
quelle
Antworten:
GCC kann das nicht, aber GDB (ein Debugger ) kann es sicher. Kompilieren Sie Ihr Programm mit dem
-g
Schalter wie folgt:Dann benutze gdb:
Hier ist ein nettes Tutorial, um Ihnen den Einstieg in GDB zu erleichtern.
Wo der Segfault auftritt, ist im Allgemeinen nur ein Hinweis darauf, wo "der Fehler, der ihn verursacht", im Code enthalten ist. Der angegebene Ort ist nicht unbedingt der Ort, an dem das Problem liegt.
quelle
bt
als Abkürzung fürbacktrace
.Sie können es auch
valgrind
versuchen: Wenn Sie installierenvalgrind
und ausführenAnschließend wird Ihr Programm ausgeführt und Stack-Traces für alle Segfaults sowie für ungültige Speicherlese- oder -schreibvorgänge und Speicherlecks angezeigt. Es ist wirklich sehr nützlich.
quelle
--leak-check=full
wird nicht helfen, Segfaults zu debuggen. Es ist nur zum Debuggen von Speicherlecks nützlich.Sie können auch einen Core-Dump verwenden und ihn dann mit gdb untersuchen. Um nützliche Informationen zu erhalten, müssen Sie auch mit dem
-g
Flag kompilieren .Wann immer Sie die Nachricht erhalten:
Eine Kerndatei wird in Ihr aktuelles Verzeichnis geschrieben. Und Sie können es mit dem Befehl überprüfen
Die Datei enthält den Status des Speichers, als das Programm abstürzte. Ein Core-Dump kann während der Bereitstellung Ihrer Software hilfreich sein.
Stellen Sie sicher, dass Ihr System die Größe der Core-Dump-Datei nicht auf Null setzt. Sie können es auf unbegrenzt einstellen mit:
ulimit -c unlimited
Vorsicht! dass Core Dumps riesig werden können.
quelle
Es gibt eine Reihe von Tools, die beim Debuggen von Segmentierungsfehlern helfen, und ich möchte mein Lieblingswerkzeug zur Liste hinzufügen: Address Sanitizers (häufig als ASAN abgekürzt) .
Moderne¹ Compiler werden mit dem praktischen
-fsanitize=address
Flag geliefert , das einige Kompilierungs- und Laufzeitkosten hinzufügt, wodurch mehr Fehler überprüft werden.Gemäß der Dokumentation umfassen diese Überprüfungen standardmäßig das Abfangen von Segmentierungsfehlern. Der Vorteil hierbei ist, dass Sie einen Stack-Trace erhalten, der der Ausgabe von gdb ähnelt, ohne das Programm jedoch in einem Debugger auszuführen. Ein Beispiel:
Die Ausgabe ist etwas komplizierter als die Ausgabe von GDB, aber es gibt Vorteile:
Es ist nicht erforderlich, das Problem zu reproduzieren, um eine Stapelverfolgung zu erhalten. Es reicht aus, das Flag während der Entwicklung zu aktivieren.
ASANs erfassen weit mehr als nur Segmentierungsfehler. Viele Zugriffe außerhalb der Grenzen werden abgefangen, selbst wenn dieser Speicherbereich für den Prozess zugänglich war.
¹ Das sind Clang 3.1+ und GCC 4.8+ .
quelle
Lucas 'Antwort zu Core Dumps ist gut. In meiner .cshrc habe ich:
um die Rückverfolgung durch Eingabe von 'core' anzuzeigen. Und der Datumsstempel, um sicherzustellen, dass ich mir die richtige Datei ansehe :(.
Hinzugefügt : Liegt ein Stapel Korruption Fehler, dann wird der Backtrace auf den Core - Dump angewandt wird oft Müll. In diesem Fall kann das Ausführen des Programms innerhalb von gdb gemäß der akzeptierten Antwort zu besseren Ergebnissen führen (vorausgesetzt, der Fehler ist leicht reproduzierbar). Achten Sie auch darauf, dass mehrere Prozesse gleichzeitig den Kern entleeren. Einige Betriebssysteme fügen die PID zum Namen der Kerndatei hinzu.
quelle
ulimit -c unlimited
Core Dumps zu aktivieren.Alle oben genannten Antworten sind korrekt und werden empfohlen. Diese Antwort ist nur als letztes Mittel gedacht, wenn keiner der oben genannten Ansätze verwendet werden kann.
Wenn alles andere fehlschlägt, können Sie Ihr Programm jederzeit mit verschiedenen temporären Debug-Print-Anweisungen (z. B.
fprintf(stderr, "CHECKPOINT REACHED @ %s:%i\n", __FILE__, __LINE__);
) neu kompilieren, die über die Ihrer Meinung nach relevanten Teile Ihres Codes verteilt sind. Führen Sie dann das Programm aus und beobachten Sie, was der letzte Debug-Druck war, der kurz vor dem Absturz gedruckt wurde. Sie wissen, dass Ihr Programm so weit gekommen ist. Der Absturz muss also nach diesem Zeitpunkt stattgefunden haben. Fügen Sie Debug-Ausdrucke hinzu oder entfernen Sie sie, kompilieren Sie sie erneut und führen Sie den Test erneut aus, bis Sie ihn auf eine einzelne Codezeile eingegrenzt haben. An diesem Punkt können Sie den Fehler beheben und alle temporären Debug-Ausdrucke entfernen.Es ist ziemlich langweilig, aber es hat den Vorteil, dass es fast überall funktioniert - das einzige Mal, wenn Sie aus irgendeinem Grund keinen Zugriff auf stdout oder stderr haben oder wenn der Fehler, den Sie beheben möchten, ein Rennen ist -Bedingung, deren Verhalten sich ändert, wenn sich das Timing des Programms ändert (da die Debug-Drucke das Programm verlangsamen und sein Timing ändern)
quelle