EMZETT.
Login

Valgrind und Sanitizer: Speicherfehler finden

Kurz: Werkzeuge, die beim Ausführen eines Programms Fehler im Umgang mit Speicher aufspüren, etwa Zugriffe außerhalb von Arrays oder vergessene Freigaben.

Genauer: In Sprachen wie C und C++ verwaltet man Speicher selbst. Typische Fehler: Zugriff hinter dem Ende eines Arrays (Buffer Overflow), Nutzung von freigegebenem Speicher (Use-after-free), mehrfaches Freigeben (Double Free), Vergessen der Freigabe (Speicherleck) und nicht initialisierte Werte. Sie führen zu Abstürzen, seltsamen Ergebnissen und Sicherheitslücken, und sind ohne Hilfe schwer zu finden.

Im Detail

Valgrind (Memcheck)

Valgrind führt das Programm in einer simulierten CPU aus und prüft jeden Speicherzugriff.

gcc -g -O0 -o prog prog.c
valgrind --leak-check=full ./prog

Die Ausgabe nennt Art des Fehlers und Quellzeile (daher -g beim Kompilieren), zum Beispiel „Invalid write of size 4 at … by main (prog.c:12)“ und „definitely lost: 40 bytes in 1 blocks“. Nachteil: Das Programm läuft 10- bis 50-mal langsamer.

AddressSanitizer (ASan)

Compiler wie GCC und Clang bauen die Prüfungen direkt in das Programm ein:

gcc -g -fsanitize=address -o prog prog.c
./prog

Die Verlangsamung ist mit etwa Faktor 2 viel geringer, und es findet Pufferüberläufe, Use-after-free und Lecks (LeakSanitizer). Weitere Sanitizer: UBSan (undefiniertes Verhalten wie Ganzzahl-Überlauf), TSan (Race Conditions zwischen Threads), MSan (nicht initialisierter Speicher).

Einsatz im Alltag

Beim Entwickeln und in automatischen Tests mit Sanitizern laufen lassen, bevor Fehler im Betrieb auftauchen. Zusammen mit Fuzzing (zufällige Eingaben) findet man so viele Sicherheitslücken. Wichtig: Das Programm muss die fehlerhafte Stelle auch ausführen, die Prüfung findet nur, was getestet wird.

Andere Sprachen

Speichersichere Sprachen wie Rust, Go, Java oder Python verhindern viele dieser Fehler durch ihr Design (Ownership, Garbage Collector). Auch dort helfen Werkzeuge, etwa Profiler für Speicherlecks durch aufgehobene Referenzen. In Rust beschränkt sich das Problem auf unsafe-Blöcke, die man mit Miri prüfen kann.

Siehe auch: Speicherleck, Stack und Heap, Fuzzing, Debugger und Core-Dumps