Segmentation fault identifizieren



  • Hallo

    Ich bekam beim ausführen meines C++ Programms die Meldung segmentation fault.

    In meinem Fall wusste ich wo der Schuh genau drückt (weil ich ein Array benötige, dass 536870912 Zeichen beinhaltet) doch wenn man mehrere Variablen hat, wäre das schon unschön, wenn das dann von Hand gesucht werden muss.

    Nach etwas Recherche und Lesen in meinem C++ Lehrbuch kam ich auf den Operator new zum dynamischen Speicher zuweisen. Ich habe das dann so gemacht und der Fehler kam dann nicht mehr und das Programm funktionierte.

    Was mich jetzt stört ist, dass mir mein Compiler (g++) keine Warnung ausgab und das Programm beim Ausführen einfach abschmierte (ich nutzte im g++ beim compilieren die Optionen -Wall und -g).

    Gibt es eine Möglichkeit sich anzeigen zu lassen wo der Fehler segmentation fault genau auftritt?

    Oder lautet eine "C++ Maxime" hier, dass man kategorisch Variablen, wo man glaubt deren Speicher reicht nicht aus, dynamisch setzt mit dem new Operator?

    Vielen Dank und entschuldigt bitte die vielleicht dumme Frage. Ich lerne erst seit sehr kurzer Zeit C++

    Grüße
    cpp_Jungspund


  • Mod

    Was du suchst, ist vermutlich ein Debugger. Selbst wenn du keinen Debugger suchtest, ist es trotzdem nützlich, sich mit Debuggern kundig zu machen.

    Speziell bei Problemen mit Speicherverwaltung gibt es auch spezialisiertere Programme, beispielsweise unter Linux das beliebte valgrind. Das diagnostiziert sehr viele typische Fehler automatisch.

    Die genannten Programme arbeiten jedoch alle zur Laufzeit. Und sind nicht unbedingt einfach zu bedienen. Und benötigen Erfahrung in der Interpretation der Ergebnisse. Das liegt einfach in der Natur der Sache, dass man diese Form von Problem eigentlich nur zur Laufzeit erkennen kann. Und diese Diagnoseprogramme geben einfach an, was gerade passiert. Die relevanten Informationen heraus zu filtern und zu verstehen ist Sache des Benutzers.

    new wirst du in C++ eigentlich nie benötigen. Du wirst zwar jede Menge Dinge benutzen, die irgendwo ganz tief im Inneren new benutzen, aber du selber wirst damit praktisch nie in Kontakt kommen, es sei denn vielleicht 1-2x zur Übung und um zu verstehen, wie die anderen Konstrukte intern arbeiten. So böte sich beispielsweise in diesem Fall doch sehr stark die Nutzung von std::vector an. Das ist ein Array mit dynamischer Größe, was aber auch den Nebeneffekt hat, dass dieses Array im Freispeicher liegen wird, wodurch der Fehler, den du hier beobachtest hast (dir ist der automatische Speicher voll geworden) vermieden wird. Intern mag der vector vielleicht irgendwo new benutzen, aber du selbst brauchst dich gar nicht darum zu kümmern.

    Alternativ kannst du natürlich auch die Größe des automatischen Speichers anpassen. Je nach System kann das sehr einfach oder sehr schwierig sein. Aber wahrscheinlich ist es den Aufwand nicht wert, dies überhaupt herauszufinden, wenn die Alternative, std::vector, derart einfach ist.



  • Hi

    Danke für den Verweis zu valgrind. Ich habe es eben installiert (war sogar in den Standard Repository enthalten 🙂 ) und mir mit google ein ein Tutorial das mir auf den ersten Blick gefällt ausgesucht. Das versuche ich am Wochenende durch zu arbeiten.

    std::vector werde ich mir heute mal genauer ansehen. Scheint so als wenn ich das gut brauchen kann und sollte.

    Gruß
    cpp_Jungspund



  • Ein Segmentation fault erzeugt eine core-Datei. Zumindest wenn das so eingestellt ist. Rufst Du das Programm dann mit dem Kommandozeilendebugger gdb und dem core-File auf (also "gdb deinprogramm core"), kannst Du mit dem Kommando "where" den Stack anschauen. Da siehst Du dann, wo es abgestürzt ist.


  • Mod

    Man sollte vielleicht noch erwähnen, dass in allen diesen Fällen - valgrind, Debugger zur Laufzeit, Debugger mit Corefile - ein Segmentation Fault durch ein übergroßes Stackobjekt ziemlich geheimnisvoll aussieht. Denn der Fehler wird beim Eintritt in die Funktion passieren (also eventuell auch der main-Funktion ganz am Anfang) und nicht mit der Zeile im Quellcode in Verbindung gebracht werden, in der das Objekt definiert wird. Denn eine Definition ist keine Anweisung im Quellcode die irgendwie in Maschinencode umgewandelt wird, sondern etwas das beeinflusst, wie eine Funktion genau aufgerufen wird. Das ist dann die von mir erwähnte nötige Erfahrung bei der Interpretation der Ergebnisse. Hier also das Wissen, dass ein Verweis auf einen Funktionsanfang oftmals irgendwie etwas mit den Objekten auf dem Stack zu tun hat.



  • cpp_Jungspund schrieb:

    Danke für den Verweis zu valgrind. Ich habe es eben installiert (war sogar in den Standard Repository enthalten 🙂 ) und mir mit google ein ein Tutorial das mir auf den ersten Blick gefällt ausgesucht. Das versuche ich am Wochenende durch zu arbeiten.

    Ich denke Valgrind ist vielleicht erstmal ein etwas zu schweres Geschütz, für jemanden, der scheinbar gerade erst davon gehört hat, dass es auch so etwas wie Debugger gibt. Ich würde es erst einmal mit GDB versuchen - wenn du mit einer IDE arbeitest, dann hast du wahrscheinlich in der nähe deines "Ausführen"-Buttons auch einen ähnlich designten "Debuggen"-Button, mit dem das Programm dann im Debugger gestartet wird.

    Ich bin leider ein wenig Visual Studio geschädigt und weiss leider nicht mehr genau wie das alles unter gcc/clang/gdb und anderen IDEs aussieht, aber eigentlich würde ich erwarten, dass wenn dein Programm auf einen Segmentation Fault läuft, die IDE mithilfe des Debuggers direkt an die Stelle in deinem Quellcode springt und dir mitteilt dass dort eine Zugriffsverletzung oder ein Stack-Überlauf stattgefunden hat. Der weitere Kontext sollte dann aus dem Callstack ersichtlich werden, den dir die IDE dann hoffenltich auch irgendwo anzeigt.

    Ohne IDE, via Kommandozeile ist das ein wenig mühsahmer (GDB-Doku), aber dennoch würde ich erstmal GDB darauf ansetzen.

    Finnegan


Anmelden zum Antworten