Valgrind
Challenge Gallery
Quick Reference
Basic workflow:
gcc -g -Wall -o program program.c # Compile with debug info
valgrind --leak-check=full ./program # Run under Valgrind
What to look for:
| Valgrind says | Meaning | Fix |
|---|---|---|
All heap blocks were freed |
No leaks | You’re done |
definitely lost: N bytes |
Memory leak | Add missing free() |
Invalid read of size N |
Reading memory you don’t own | Check array bounds, check for use-after-free |
Invalid write of size N |
Writing memory you don’t own | Check buffer sizes, check for use-after-free |
Invalid free() |
Double free or freeing non-heap memory | Remove duplicate free() |
uninitialised value |
Using uninitialized memory | Use calloc or initialize before reading |
N allocs, M frees |
Should be equal | Find the N-M missing free() calls |
Reading the output:
==12345== Invalid read of size 4 ← What: reading 4 bytes illegally
==12345== at 0x40069C: main (prog.c:7) ← Where: line 7 of prog.c
==12345== Address is 0 bytes after a ← Why: right past end of
==12345== block of size 20 alloc'd ← a 20-byte allocation
==12345== at 0x4C2ABCD: calloc ← Origin: allocated via calloc
==12345== by 0x401200: main (prog.c:4) ← at line 4
Common Pitfalls
- Forgetting
-g— Without debug symbols, Valgrind shows hex addresses instead of file:line. - Testing only the happy path — Valgrind only catches bugs that execute. Test edge cases.
- Ignoring “still reachable” — Usually not a bug, but clean it up for good hygiene.
- Nested allocations — A struct with
char *nameneeds TWO frees. Valgrind counts each. - Reading Valgrind output bottom-up — The allocation origin is at the bottom. The error location is at the top.