Ich schreibe ein plattformübergreifendes C ++ - Programm für Windows und Unix. Auf der Fensterseite wird der Code problemlos kompiliert und ausgeführt. Auf der Unix-Seite wird es jedoch kompiliert, wenn ich versuche, es auszuführen, wird ein Segmentierungsfehler angezeigt. Meine anfängliche Vermutung ist, dass es ein Problem mit Zeigern gibt.
Was sind gute Methoden, um Segmentierungsfehler zu finden und zu beheben?
quelle
g
im Kontext von kompilieren zu lassenCMake
?cmake -DCMAKE_BUILD_TYPE=Debug
.Manchmal ist der Absturz selbst nicht die eigentliche Ursache des Problems - vielleicht wurde der Speicher zu einem früheren Zeitpunkt zerstört, aber es dauerte eine Weile, bis sich die Korruption zeigte. Schauen Sie sich valgrind an , das viele Überprüfungen auf Zeigerprobleme enthält (einschließlich der Überprüfung der Arraygrenzen). Hier erfahren Sie, wo das Problem beginnt und nicht nur in welcher Zeile der Absturz auftritt.
quelle
Versuchen Sie, das Problem so weit wie möglich zu vermeiden, bevor es auftritt:
Verwenden Sie zum Debuggen geeignete Tools. Unter Unix:
Mit GCC können Sie auch Schmutzfänger verwenden.Mit GCC, Clang und seit Oktober experimentell MSVC können Sie Address / Memory Sanitizer verwenden . Es kann einige Fehler erkennen, die Valgrind nicht erkennt, und der Leistungsverlust ist geringer. Es wird durch Kompilieren mit dem-fsanitize=address
Flag verwendet.Zum Schluss würde ich die üblichen Dinge empfehlen. Je besser Ihr Programm lesbar, wartbar, klar und ordentlich ist, desto einfacher ist das Debuggen.
quelle
Unter Unix können
valgrind
Sie Probleme finden. Es ist kostenlos und mächtig. Wenn Sie es lieber selbst tun möchten, können Sie die Operatorennew
und überladendelete
, um eine Konfiguration einzurichten, bei der Sie0xDEADBEEF
vor und nach jedem neuen Objekt 1 Byte haben . Verfolgen Sie dann, was bei jeder Iteration passiert. Dies kann nicht alles erfassen (es ist nicht garantiert, dass Sie diese Bytes berühren), aber es hat in der Vergangenheit auf einer Windows-Plattform für mich funktioniert.quelle
new
unddelete
sehr nützlich sein kann, ist die Verwendung-fsanitize=address
eine bessere Option, da der Compiler bei der Laufzeiterkennung nach Problemen kompiliert und den Speicher automatisch auf dem Bildschirm ablegt, was das Debuggen erleichtert.Ja, es gibt ein Problem mit Zeigern. Sehr wahrscheinlich verwenden Sie eine, die nicht richtig initialisiert wurde, aber es ist auch möglich, dass Sie Ihre Speicherverwaltung mit doppelten Freigaben oder Ähnlichem durcheinander bringen.
Um nicht initialisierte Zeiger als lokale Variablen zu vermeiden, versuchen Sie, sie so spät wie möglich zu deklarieren, vorzugsweise (und dies ist nicht immer möglich), wenn sie mit einem aussagekräftigen Wert initialisiert werden können. Überzeugen Sie sich selbst, dass sie einen Wert haben, bevor sie verwendet werden, indem Sie den Code untersuchen. Wenn Sie damit Schwierigkeiten haben, initialisieren Sie sie mit einer Nullzeigerkonstante (normalerweise als
NULL
oder geschrieben0
) und überprüfen Sie sie.Um nicht initialisierte Zeiger als Elementwerte zu vermeiden, stellen Sie sicher, dass sie im Konstruktor ordnungsgemäß initialisiert und in Kopierkonstruktoren und Zuweisungsoperatoren ordnungsgemäß behandelt werden. Verlassen Sie sich nicht auf eine
init
bei der Speicherverwaltung Funktion, auch bei anderen Initialisierungen.Wenn Ihre Klasse keine Kopierkonstruktoren oder Zuweisungsoperatoren benötigt, können Sie diese als private Elementfunktionen deklarieren und niemals definieren. Dies führt zu einem Compilerfehler, wenn diese explizit oder implizit verwendet werden.
Verwenden Sie gegebenenfalls intelligente Zeiger. Der große Vorteil dabei ist, dass Sie das Schreiben vollständig vermeiden können, wenn Sie sich an sie halten und sie konsequent verwenden,
delete
und nichts wird doppelt gelöscht.Verwenden Sie nach Möglichkeit C ++ - Zeichenfolgen und Containerklassen anstelle von Zeichenfolgen und Arrays im C-Stil. Verwenden Sie
.at(i)
lieber als[i]
, da dies die Überprüfung der Grenzen erzwingt. Überprüfen Sie, ob Ihr Compiler oder Ihre Bibliothek so eingestellt werden kann, dass die Grenzen überprüft werden[i]
zumindest im Debug-Modus werden. Segmentierungsfehler können durch Pufferüberläufe verursacht werden, die Müll über einwandfreie Zeiger schreiben.Dadurch wird die Wahrscheinlichkeit von Segmentierungsfehlern und anderen Speicherproblemen erheblich verringert. Sie werden zweifellos nicht in der Lage sein, alles zu reparieren, und deshalb sollten Sie ab und zu Valgrind verwenden, wenn Sie keine Probleme haben, und Valgrind und GDB, wenn Sie dies tun.
quelle
Ich kenne keine Methode, um solche Probleme zu beheben. Ich denke nicht, dass es möglich wäre, eine zu finden, denn das eigentliche Problem ist, dass das Verhalten Ihres Programms undefiniert ist (ich kenne keinen Fall, in dem SEGFAULT nicht durch irgendeine Art von UB verursacht wurde). .
Es gibt alle Arten von "Methoden", um das Problem zu vermeiden, bevor es auftritt. Ein wichtiger ist RAII.
Außerdem musst du nur deine besten psychischen Energien darauf werfen.
quelle