[Powered by Google Translate] [Valgrind]
[Nate Hardison, Harvard University]
Dies ist CS50, CS50.TV]
Einige der schwierigsten Fehler in C-Programmen
kommen aus dem Missmanagement der Erinnerung.
Es gibt eine große Anzahl von Möglichkeiten, Dinge zu vermasseln,
einschließlich Zuweisung die falsche Menge an Speicher,
vergessen, Variablen zu initialisieren,
Schreiben vor oder nach dem Ende eines Puffers,
und Befreiung zu halten Speicher mehrmals.
Die Symptome reichen von unerwarteten Abstürzen
auf mysteriöse Weise überschrieben Werte,
oft an Orten und zu Zeiten weit von der ursprünglichen Fehler entfernt.
Auf den Spuren der beobachteten Problem wieder auf die zugrunde liegende Ursache
kann eine Herausforderung sein,
aber zum Glück gibt es eine hilfreiche Programm namens Valgrind
das kann viel tun, um zu helfen.
>> Sie führen ein Programm unter Valgrind zu ermöglichen
umfangreiche Überprüfung des Heap-Speichers Zuweisungen und Zugänge.
Wenn Valgrind ein Problem erkennt, gibt es Ihnen sofort,
direkte Informationen, die Ihnen erlaubt,
leichter zu finden und das Problem beheben.
Valgrind auch Berichte über weniger tödlich Probleme mit dem Arbeitsspeicher,
wie Speicherlecks, Zuteilung Heap-Speicher,
und vergessen, sie zu befreien.
Wie unsere Compiler, Clang in unserem Debugger GDB,
Valgrind ist freie Software, und es wird auf dem Gerät installiert.
Valgrind läuft auf Ihrem Binärformat,
nicht Ihre. c oder. h Quellcodedateien,
so sicher sein, Sie haben eine up-to-date Kopie Ihrer Programm kompiliert
Verwendung Clang Oder.
Dann kann Ihr Programm unter Valgrind werden
so einfach wie nur voranstellen das Standard-Programm-Befehl mit dem Wort Valgrind,
die startet Valgrind und läuft das Programm im Inneren.
Beim Starten tut Valgrind einige komplexe
Überdrehen um die ausführbare Datei für die Speicher-Überprüfungen konfigurieren,
so kann es noch ein bisschen aufstehen und laufen.
Das Programm wird dann normal ausgeführt, sei es viel langsamer,
und wenn es fertig ist, wird Valgrind drucken eine Zusammenfassung seiner Speichernutzung.
Wenn alles gut geht, wird es in etwa so aussehen:
In diesem Fall. / Clean_program
ist der Pfad zu dem Programm, das ich ausführen möchten.
Und während dieses hat keine Argumente,
wenn es das täte würde ich nur tack sie an das Ende des Befehls wie gewohnt.
Saubere Programm ist nur ein dummes kleines Programm habe ich
das Speicherplatz für einen Block von ints auf dem Heap,
setzen einige Werte innerhalb von ihnen, und befreit den ganzen Block.
Dies ist, was Sie suchen, ohne Fehler und ohne Lecks schießen.
>> Eine weitere wichtige Metrik ist die Gesamtanzahl von zugewiesenen Bytes.
Je nach Programm, wenn Ihr Zuweisungen in den Megabyte oder höher sind,
sind Sie wahrscheinlich etwas falsch machen.
Sind Sie nicht unnötig speichert Duplikate?
Sind Sie mit dem Heap für Lagerung, wenn es besser wäre, den Stapel zu verwenden?
So kann der Speicher Fehler wirklich böse.
Je mehr offene Hosen zu spektakulären Stürzen,
aber selbst dann kann es immer noch schwer zu lokalisieren
was genau führte zum Absturz.
Mehr schleichend, ein Programm mit einer Speicher-Fehler
kann noch sauber kompilieren
und scheinen immer noch korrekt funktionieren
weil du es geschafft, mit etwas Glück die meisten der Zeit.
Nach mehreren "erfolgreichen Ergebnissen"
Sie können nur denken, dass ein Crash ein Glücksfall des Computers ist,
aber der Computer ist nie verkehrt.
>> Laufen Valgrind können Ihnen helfen, die Spur der Ursache der sichtbare Speicher Fehler
sowie zu finden lauern Fehler, die Sie noch gar nicht kennen.
Jedes Mal, wenn Valgrind ein Problem feststellt, druckt es Informationen darüber, was es beobachtet.
Jedes Element ist ziemlich knappe -
die Source-Leitung des betreffenden Anweisung, was das Problem ist,
und ein wenig Informationen über den Speicher beteiligt -
aber oft ist es genug Informationen, um Ihre Aufmerksamkeit auf die richtige Stelle weiter.
Hier ist ein Beispiel für Valgrind läuft auf einem Buggy-Programm
das tut eine ungültige Lesen von Heap-Speicher.
Wir sehen keine Fehler oder Warnungen in der Zusammenstellung.
Uh-oh, sagt der Fehler Zusammenfassung, dass es zwei Fehler -
zwei ungültige Lesevorgänge der Größe 4 - Byte, das ist.
Beide schlechten liest traten in der Hauptfunktion invalid_read.c,
die erste auf der Leitung 16 und der zweiten auf der Leitung 19.
Lassen Sie uns auf den Code schauen.
Sieht aus wie der erste Aufruf von printf versucht, ein int über das Ende unserer Speicherblock gelesen.
Wenn wir blicken zurück auf Valgrind-Ausgang,
sehen wir, dass Valgrind uns gesagt, genau dies.
Die Adresse, die wir versuchen zu lesen sind beginnt 0 Byte
über das Ende des Blocks der Größe 16 Bytes -
vier 32-Bit-Ganzzahlen dass wir zugeordnet.
Das ist, beginnt die Adresse, die wir versuchen zu lesen waren ganz am Ende unseres Blocks,
wie wir sehen in unserer schlechten printf.
Nun könnte ungültige Lesevorgänge nicht wie die große Sache scheinen,
aber wenn Sie mit, dass die Daten, um den Fluss des Programms zu kontrollieren -
zum Beispiel als Teil einer if-Anweisung oder eine Schleife -
dann kann es lautlos gehen schlecht.
Beobachten Sie, wie kann ich die invalid_read Programm ausführen
und nichts aus dem Üblichen heraus geschieht.
Scary, huh?
>> Lassen Sie uns nun auf einige weitere Arten von Fehlern, die Sie in Ihrem Code auftreten aussehen könnte,
und wir werden sehen, wie Valgrind sie erkennt.
Wir sahen nur ein Beispiel für eine invalid_read,
so jetzt lasst uns bitte eine invalid_write.
Wieder keine Fehler oder Warnungen in der Zusammenstellung.
Ausreichend, sagt Valgrind dass es zwei Fehler in diesem Programm -
und invalid_write und ein invalid_read.
Sehen wir uns diesen Code.
Sieht aus wie wir eine Instanz des klassischen strlen plus ein bug habe.
Der Code nicht malloc ein zusätzliches Byte Platz
für die / 0 Charakter,
so, wenn str Kopie an es ssubstrlen schreiben ging "CS50 rocks!"
schrieb er 1 Byte über das Ende unseres Blocks.
Die invalid_read kommt, wenn wir unseren Aufruf printf machen.
Printf endet Lesen ungültigen Speicherzugriff, wenn es die / 0 Zeichen liest
wie es am Ende dieser E-Saite sieht es Druck.
Aber nichts davon entgangen Valgrind.
Wir sehen, dass es die invalid_write gefangen, als Teil des str Kopie
on line 11 von Haupt-, und die invalid_read ist Teil printf.
Rock on, Valgrind.
Wiederum kann dies nicht wie eine große Sache zu sein scheinen.
Wir können dieses Programm über und über laufen außerhalb der Valgrind
und sehen keine Fehlersymptome.
>> Aber lassen Sie in einem leichten Variation aussehen zu sehen
wie die Dinge können sich wirklich schlecht.
So gewährte, sind wir missbrauchen Dinge mehr als nur ein bisschen in diesem Code.
Wir sind nur Zuweisung von Speicherplatz auf dem Heap für zwei Strings
die Länge des CS50 Felsen,
dieses Mal die Erinnerung an die / 0 Charakter.
Aber dann haben wir in einem super-langen Schnur zu werfen in den Speicherblock
das S verweist.
Welche Auswirkungen hat das auf den Speicherblock, dass T Punkte?
Nun, wenn T Punkten auf Speicher, direkt neben S ist,
kommen kurz danach,
dann könnten wir über einen Teil T. geschrieben haben
Lassen Sie diesen Code ausführen.
Schauen Sie, was passiert ist.
Die Saiten wir in unserem Heapblöcke beiden gespeicherten schien korrekt gedruckt wurden.
Nichts scheint überhaupt falsch.
Allerdings gehen wir zurück in unser Code und
kommentieren Sie die Zeile, wo wir CS50 Felsen kopieren
in den zweiten Speicherblock, auf den durch t.
Nun, wenn wir diesen Code ausführen sollten wir
sehen nur den Inhalt des ersten Speicherblock auszudrucken.
Whoa, obwohl wir nicht str Kopie
alle Zeichen in die zweite Heap-Block wies die ein durch T,
erhalten wir einen Ausdruck.
In der Tat, die Zeichenfolge wir gefüllt in unserer ersten Block
überstieg den ersten Block und in den zweiten Block,
macht alles scheint normal.
Valgrind, obwohl, erzählt uns die wahre Geschichte.
Dort gehen wir.
Alle diejenigen, ungültige liest und schreibt.
>> Lassen Sie uns auf ein Beispiel für eine andere Art von Fehler zu suchen.
Hier haben wir etwas tun, eher unglücklich.
Wir schnappen Platz für ein int auf dem Heap,
und initialisieren wir einen int-Zeiger - p - zu diesem Raum zeigen.
Doch während unsere Zeiger initialisiert wird,
die Daten, dass es auf den Hinweis soeben was immer Junk ist in dem Teil des Haufens.
Also, wenn wir die Daten laden in int i,
wir technisch initialisieren i,
aber wir tun dies mit Datenmüll.
Der Aufruf zu behaupten, das ist ein handliches Debugging Makro
definiert in der treffend benannte behaupten Bibliothek,
bricht das Programm, ob seine Test Bedingung nicht erfüllt.
Das heißt, wenn ich nicht gleich 0 ist.
Je nachdem, was war in der Heap-Speicher, auf den durch p,
Dieses Programm könnte manchmal arbeiten und nicht zu anderen Zeiten.
Wenn es funktioniert, sind wir nur immer Glück.
Der Compiler wird nicht fangen diesen Fehler, aber Valgrind sicher Willen.
Dort sehen wir den Fehler, die sich aus unseren Verwendung dieser Datenmüll.
>> Wenn Sie Heap-Speicher zugewiesen, aber nicht freigeben es oder befreien sie,
Das nennt man ein Leck.
Für eine kleine, kurzlebige Programm, und läuft sofort beendet,
Undichtigkeiten sind ziemlich harmlos,
aber für ein Projekt der größeren Größe und / oder Langlebigkeit,
sogar ein kleines Leck kann in etwas größeren verschlimmern.
Für CS50, wir erwarten, dass Sie
kümmern zu befreien alle Heap-Speicher, die Sie zuweisen,
da wir möchten, dass Sie die Fähigkeiten aufbauen, um ordnungsgemäß zu behandeln den manuellen Prozess
Bedarf von C.
Um dies zu tun, sollte Ihr Programm eine genaue
Eins-zu-eins-Entsprechung zwischen malloc und free Anrufe.
Glücklicherweise kann Valgrind Sie mit Speicherlecks zu helfen.
Hier ist eine undichte Programm namens leak.c, dass zuweist
Speicherraum in dem Haufen, schreibt in ihn, aber nicht befreit werden.
Wir erarbeiten mit Marke und führen Sie es unter Valgrind,
und wir sehen, dass, während wir keine Memory-Fehler haben,
wir haben ein Leck.
Es gibt 16 Bytes endgültig verloren,
bedeutet, dass der Zeiger auf diesen Speicher nicht im Bereich, wenn das Programm beendet wird.
Nun bedeutet Valgrind uns nicht eine Unmenge an Informationen über das Leck,
aber wenn wir diesen kleinen Zettel, dass es sich ergibt nach unten seines Berichts
mit erneut - Leck-Check = full
um die vollen Details durchgesickert Speicher zu sehen,
wir weitere Informationen erhalten.
Jetzt, in der Halde Zusammenfassung
Valgrind sagt uns, wo die Erinnerung, das verloren war ursprünglich zugewiesen wurde.
So wie wir von der Suche im Quellcode wissen,
Valgrind informiert uns, dass wir die Erinnerung durchgesickert
zugeordnet mit einem Aufruf von malloc on line 8 von leak.c
in der Funktion main.
Ziemlich raffiniert.
>> Valgrind kategorisiert Lecks mit diesen Worten:
Endgültig verloren - das ist Heap-Speicher
, auf die das Programm nicht mehr einen Zeiger.
Valgrind weiß, dass Sie hatte einmal die Zeiger, sondern seit Spur von ihm verloren.
Dieser Speicher ist definitiv durchgesickert.
Indirekt verloren - das ist Heap-Speicher
an die die nur Zeiger, um es ebenfalls verloren.
Zum Beispiel, wenn Sie verloren Ihre Zeiger auf den ersten Knoten einer verketteten Liste,
dann der erste Knoten selbst würde definitiv verloren,
während alle weiteren Knoten würde indirekt verloren.
Möglicherweise verloren - das ist Heap-Speicher
, denen Valgrind kann nicht sicher sein, ob es einen Zeiger oder nicht.
Noch erreichbar ist Heap-Speicher
zu denen das Programm noch einen Zeiger an der Ausfahrt,
das bedeutet normalerweise, dass eine globale Variable verweist.
Um diese Lecks zu überprüfen, werden Sie auch die Option beinhalten
- Immer noch erreichbar = yes
in Ihrem Aufruf von Valgrind.
>> Diese verschiedenen Fälle könnten unterschiedliche Strategien für die Reinigung sie bis erfordern,
aber Lecks sollten beseitigt werden.
Leider kann Fixierung Lecks schwer zu tun,
da eine falsche Anrufe zu kostenlosen blasen kann Ihr Programm.
Zum Beispiel, wenn wir uns invalid_free.c,
sehen wir ein Beispiel für schlechte Speicherfreigabe.
Was sollte ein einziger Anruf, um den ganzen Block zu befreien
der Speicher, auf den int_block,
Stattdessen hat sich ein Versuch, um jeden int-sized Abschnitt befreien
der Speicher individuell.
Dies wird katastrophal versagen.
Boom! Was für ein Fehler.
Dies ist definitiv nicht gut.
Wenn Sie mit dieser Art von Fehler stecken, aber, und Sie nicht wissen, wo sie suchen müssen,
zurückgreifen zu Ihrem neuen besten Freund.
Sie haben es erraten - Valgrind.
Valgrind, wie immer, weiß genau, was los ist.
Die alloc und frei zählt nicht mithalten.
Wir haben 1 alloc und 4 befreit.
Und Valgrind sagt uns auch, wo die erste schlechte kostenlosen Anruf -
derjenige, der die blowup ausgelöst - herkommt -
Linie 16.
Wie Sie sehen, sind schlechte Calls zu befreien wirklich schlecht,
so dass wir empfehlen, dass Sie Ihr Programm Leck
während du auf immer die Funktionalität richtige Arbeitshöhe.
Start der Suche nach Lecks erst nach Ihrem Programm richtig funktioniert,
ohne weitere Fehler.
>> Und das ist alles, was wir für dieses Video bekommen habe.
Nun, was wartest du noch?
Gehe laufen Valgrind auf Ihren Programmen richtig.
Mein Name ist Nate Hardison. Dies ist CS50. [CS50.TV]