Speicherzugriffsverletzung - Richtig debuggen

Schnelle objektorientierte, kompilierende Programmiersprache.
Antworten
Glocke
Beiträge: 332
Registriert: Fr Okt 26, 2012 8:39 am

Speicherzugriffsverletzung - Richtig debuggen

Beitrag von Glocke » So Jan 06, 2013 2:34 pm

Hi, ich programmiere seit Jahren ohne IDEs, d.h. nur mit Texteditor und Terminal (in meinem Fall gedit und gnome-terminal unter Linux Ubuntu).

Gerade bei C++ ist mir aufgefallen, dass das Debuggen recht komplex ist - vor allem bei Speicherzugriffsverletzungen. Bisher gehe ich folgendermaßen vor, wenn sich mein Programm an einem NULL-Pointer verschluckt hat:
  • Mittels Valgrind (genauer verwende ich die GUI "alleyoop") finde ich raus, in welcher Funktion bzw. Methode das Problem auftritt. Damit kenne ich meist auch die Zeilennummer, die verdächtiger Weise in Frage kommt.
  • Allerdings ist die Ausgabe von Valgrind für mich nicht immer eindeutig (sorry, dass ich jetzt kein Beispiel parat hab, aber manchmal frag ich mich "Was mag der an der Stelle jetzt nicht?").
  • Wenn ich die Stelle noch nicht gefunden habe, setze ich Testausgaben (std::cout << "Foo: " << (foo != NULL) << std::endl;) um herauszufinden, wo der Zeiger (un-)gültig ist. Dabei schaue ich mir auch "übergeordnete" Funktionen / Methoden (damit meine ich solche, die die eigentliche "Problem-Funktion/-Methode" aufrufen und Zugriff auf den Zeiger (Klassenmember, Parameter usw.) haben). Vermutlich ist das erheblich mehr Aufwand als überhaupt notwendig.
Mein Problem damit ist, dass es einerseits lange dauert die verdächtigen Stellen zu finden, und zusätzlich das Ausführen des Programms mit Valgrind extrem langsam ist. Ist das so normal? Ich hab' es auf meinem Netbook (ja, nix schnelles ^^) und auf meinem Desktop (der eigentlich einige Ecken schneller ist) getestet: auf dem Desktop ist es minimal schneller.
Liegt die Geschwindigkeitseinbuße an Valgrind? (btw arbeite ich mit SDL und kompiliere natürlich die Debugging-Symbole mit g++ in das Programm rein)

Zusätzlich arbeite ich mit GDB (als GUI "nemiver"). Nur hilft der mir oftmals nicht weiter. Anstatt er mir (mit Nemiver kann ich mir ja den Quellcode ansehen und Haltepunkte setzen) die Stelle liefert (an der die Speicherzugriffsverletzung auftaucht), zeigt er mir nur Assembler-Code (oder etwas derartiges - da bin ich nicht ganz auf der Höhe - sieht in jedem Fall sehr maschinen nah aus) an. Zum Debuggen hilft mir das nicht :?
Und erstmal gefühlte Tausend Haltepunkte zu setzen, klingt für mich nicht nach effektiver Fehlersuche :lol:

Lange Rede - kurzer Sinn: Wie debugge ich richtig?

LG Glocke

Benutzeravatar
fat-lobyte
Beiträge: 1398
Registriert: Sa Jul 05, 2008 12:23 pm
Wohnort: ::1
Kontaktdaten:

Re: Speicherzugriffsverletzung - Richtig debuggen

Beitrag von fat-lobyte » So Jan 06, 2013 4:37 pm

Also ich debugge meistens mit Kommandozeilen-GDB und dem Quellcode daneben.
Das ist fast "normal" schnell, nur halt ohne optimierungen.

Wichtig ist, das Program mit der "-g"-Option zu kompilieren.

Dabei kann man Breakpoints in Dateien Setzen (break qelldatei.cpp:42), variablen untersuchen ("print"), funktionen aufrufen, und auch Speicherbereiche anzeigen (x-Befehl).
Zwischen unter/übergeordneten Funktionen kann man mit dem "frame"-Befehl wechseln, und alle Frames mit dem "backtrace"-Befehl anzeigen lassen.


Vor einiger Zeit habe ich es irgendwie geschafft Codelite mit GDB zum laufen zu bringen, dort konnte ich dann auch einige Dinge debuggen.

Und hier noch ein ganz untypischer Tipp von mir: Versuchs mal mit Visual Studio. MSVC hat einen ziemlich ziemlich guten Debugger, der sehr bequem zu benutzen ist und auch ziemnlich hilfreich ist.
Haters gonna hate, potatoes gonna potate.

Glocke
Beiträge: 332
Registriert: Fr Okt 26, 2012 8:39 am

Re: Speicherzugriffsverletzung - Richtig debuggen

Beitrag von Glocke » So Jan 06, 2013 9:16 pm

fat-lobyte hat geschrieben:Also ich debugge meistens mit Kommandozeilen-GDB und dem Quellcode daneben.
Das ist fast "normal" schnell, nur halt ohne optimierungen.

Wichtig ist, das Program mit der "-g"-Option zu kompilieren.

Dabei kann man Breakpoints in Dateien Setzen (break qelldatei.cpp:42), variablen untersuchen ("print"), funktionen aufrufen, und auch Speicherbereiche anzeigen (x-Befehl).
Zwischen unter/übergeordneten Funktionen kann man mit dem "frame"-Befehl wechseln, und alle Frames mit dem "backtrace"-Befehl anzeigen lassen.
Okay, also werde ich mich mal mit GDB detailliert befassen :)
fat-lobyte hat geschrieben:Und hier noch ein ganz untypischer Tipp von mir: Versuchs mal mit Visual Studio. MSVC hat einen ziemlich ziemlich guten Debugger, der sehr bequem zu benutzen ist und auch ziemnlich hilfreich ist.
Naja ich hab keinen Windows-Rechner - und mit Wine MSVC laufen lassen ist glaube bisschen zu viel Arbeit :D
Weißt du zufällig wie es bzgl. MonoDevelop aussieht? Oder verwendet der auch GDB?

Hat noch jemand Erfahrung mit Valgrind - vor allem bzgl. der Geschwindigkeit?

LG Glocke

Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8862
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Re: Speicherzugriffsverletzung - Richtig debuggen

Beitrag von Xin » Mo Jan 07, 2013 11:18 am

Eigentlich kann ich fat-lobyte auch nur bestätigen
Glocke hat geschrieben:Hi, ich programmiere seit Jahren ohne IDEs, d.h. nur mit Texteditor und Terminal (in meinem Fall gedit und gnome-terminal unter Linux Ubuntu).

Zusätzlich arbeite ich mit GDB (als GUI "nemiver"). Nur hilft der mir oftmals nicht weiter. Anstatt er mir (mit Nemiver kann ich mir ja den Quellcode ansehen und Haltepunkte setzen) die Stelle liefert (an der die Speicherzugriffsverletzung auftaucht), zeigt er mir nur Assembler-Code (oder etwas derartiges - da bin ich nicht ganz auf der Höhe - sieht in jedem Fall sehr maschinen nah aus) an. Zum Debuggen hilft mir das nicht :?
Für gdb muss der GCC, wie fat-lobyte schon richtig sagt, mit der Option -g kompiliert werden. Dann ist das bei mir eben auch das Tool der Wahl, um derartige Fehler zu finden.
Valgrind emuliert quasi die komplette Maschine und registriert jeden(!) Speicherzugriff, ob der in einem gültigen Bereich stattgefunden hat. Das kostet viel Zeit, liefert aber eben auch viele wertvolle Informationen.

Und obwohl mich fat-lobytes Tipp mit Visual Studio erstaunt, ich kann Dir nur den selben geben. Zum einen ist es nicht verkehrt mehr als einen Compiler zum Kompilieren zu verwenden. Die Compiler entdecken unterschiedliche Fehler oder "Mängel". Und ich benutze Visual Studio auch gerne als Debugger, was vorrangig aber daran liegt, dass ich VS auch auf der Arbeit benutze und es entsprechend gewöhnt bin. Visual Studio ist für mich derzeit der Hauptgrund für eine Windows-Installation.
CodeLite und Codeblocks unterstützen aber ebenfalls Step-By-Step-Debugger.
Glocke hat geschrieben:Und erstmal gefühlte Tausend Haltepunkte zu setzen, klingt für mich nicht nach effektiver Fehlersuche :lol:
Ich vermute, Du meinst effizient, denn nicht effektiv wäre ja, dass der Fehler drin bliebe.
Fehlersuche ist niemals effizient, deswegen lernt man als Informatiker ja auch, Projekte hinreichend zu planen, um Fehler zu vermeiden. Die Realität lernt einen dann wieder, dass sich sowieso nicht alles planen lässt und man die zusätzliche Zeit für's Debuggen lieber gleich mit einplant.
Glocke hat geschrieben:Lange Rede - kurzer Sinn: Wie debugge ich richtig?
-g beim GCC verwenden - damit fängt's an.

Damit man nicht anfangen muss, vorher durchaus mal -Wall -pendantic anwerfen und der clang-Compiler findet ebenfalls gute Warnhinweise. Auch das Kompilieren mit Visual Studio war noch einige Hinweise, so dass ich auf ein, zwei Bugs aufmerksam wurde. Unittests schreiben, um Bugs in kontrollierter Umgebung abzutesten - mindestens für kompliziertere Codeabschnitte, die nicht durchgehend verwendet werden.

Programmieren besteht gerne aus ca. 50-80% Debuggen. Du kannst das drücken, indem Du semantisch starke Sprachen auch ausnutzt: Templates (vermindert Redundanz), Mehrfachvererbung (vermindert Redundanz). Redundanz vermeiden: das erhöht die Verwendung der geschriebenen Codes, entsprechend fallen Fehler schneller auf. Const-Correctness verhindert, dass man Variablen überschreibt, obwohl das in dem Moment nicht gewünscht ist. Das nachträgliche Einfügen von Const-Correctness in ein Projekt war mal eine Lehrstunde, weswegen ich keine Sprache mehr freiwillig anfasse, die Const-Correctness nicht unterstützt: Es wurden reichlich Bugs gefunden, die noch gar nicht aufgefallen waren.
Gute Programmierkenntnisse helfen also ebenfalls dabei, die Debugzeiten zu reduzieren. Die einzigen Bugs, die ich 2012 im Job zugewiesen bekam, haben andere geschrieben. Das ist Zufall, dass alles funktioniert, was ich 2012 geschrieben habe (bzw. keine Fehler aufgefallen sind), aber ein gefälliger.
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

Glocke
Beiträge: 332
Registriert: Fr Okt 26, 2012 8:39 am

Re: Speicherzugriffsverletzung - Richtig debuggen

Beitrag von Glocke » Mo Jan 07, 2013 2:40 pm

Xin hat geschrieben:-g beim GCC verwenden - damit fängt's an.
Hab ich ^^
Xin hat geschrieben:Damit man nicht anfangen muss, vorher durchaus mal -Wall -pendantic anwerfen und der clang-Compiler findet ebenfalls gute Warnhinweise. Auch das Kompilieren mit Visual Studio war noch einige Hinweise, so dass ich auf ein, zwei Bugs aufmerksam wurde. Unittests schreiben, um Bugs in kontrollierter Umgebung abzutesten - mindestens für kompliziertere Codeabschnitte, die nicht durchgehend verwendet werden.
-Wall hab ich prinzipiell an. Aber von "-pedantic" wusste ich bisher nix.
Bisher hab mich mit g++ -g -Wall -Wfatal-errors -std=c++0x foo.cpp -c gebaut und anschließend die .o-files samt Libs gelinkt.
Xin hat geschrieben:Programmieren besteht gerne aus ca. 50-80% Debuggen.
Deswegen die Frage :mrgreen:
Xin hat geschrieben:Const-Correctness verhindert, dass man Variablen überschreibt, obwohl das in dem Moment nicht gewünscht ist. Das nachträgliche Einfügen von Const-Correctness in ein Projekt war mal eine Lehrstunde, weswegen ich keine Sprache mehr freiwillig anfasse, die Const-Correctness nicht unterstützt: Es wurden reichlich Bugs gefunden, die noch gar nicht aufgefallen waren.
Okay :shock: Und ab auf die ToDo-Liste damit :?


Danke für die Anregungen! :)

LG Glocke

Antworten