Skip to content

Expert · Debugging and tools · topic 52 of 60 · 25 min

Finding memory bugs with valgrind

Explanation

valgrind's memcheck tool runs your unmodified program on a simulated CPU and reports invalid reads and writes, use of uninitialised values, invalid frees and memory leaks, with the source lines involved. Run valgrind --leak-check=full ./prog on a -g build. It works on Linux (and WSL on Windows) and slows the program down a lot, so use it on test inputs.

Running it

bash
gcc -std=c17 -g -O0 orders.c -o orders
valgrind --leak-check=full --show-leak-kinds=all ./orders test_orders.csv
No recompilation for valgrind is needed beyond -g; it checks every memory access as the program runs.

Reading the report

output
==4021== Invalid read of size 4
==4021==    at 0x10920B: sum_amounts (orders.c:17)
==4021==    by 0x1092F1: main (orders.c:40)
==4021==  Address 0x4a8f0a8 is 0 bytes after a block of size 40 alloc'd
==4021==    at 0x4846828: malloc (vg_replace_malloc.c:…)
==4021==    by 0x1092B3: main (orders.c:36)
Reading 4 bytes just past a 40-byte block (10 ints): an off-by-one loop at line 17 over memory allocated at line 36.
output
==4021== Conditional jump or move depends on uninitialised value(s)
==4021==    at 0x109240: max_amount (orders.c:24)
An if or loop used a value that was never set (often malloc'd memory or a local).
output
==4021== Invalid free() / delete / delete[] / realloc()
==4021==    at 0x48493B0: free (…)
==4021==    by 0x109312: main (orders.c:45)
==4021==  Address 0x4a8f080 is 0 bytes inside a block of size 40 free'd
A double free: the block was already freed earlier.
output
==4021== LEAK SUMMARY:
==4021==    definitely lost: 120 bytes in 3 blocks
==4021==    indirectly lost: 0 bytes in 0 blocks
==4021==      possibly lost: 0 bytes in 0 blocks
==4021==    still reachable: 0 bytes in 0 blocks
==4021== ERROR SUMMARY: 3 errors from 3 contexts
Leak kindMeaning
definitely lostNo pointer to the block remains: a real leak to fix
indirectly lostReachable only through a block that is itself lost (e.g. the rest of a leaked list)
possibly lostOnly a pointer into the middle of the block remains; usually a leak
still reachableStill pointed to at exit (e.g. a global cache never freed); often harmless, but tidy it up

Tips for using it well

  • Fix the FIRST error first; later errors are often consequences.
  • The program runs many times slower (often 10–50×), so use small test inputs.
  • Run your test suite under valgrind in CI to catch regressions.
  • valgrind and AddressSanitizer cannot be used on the same binary; use one or the other.
Careful: valgrind only reports problems on the code paths that actually ran. A clean report on one input does not prove the program is correct; test edge cases (empty files, very long lines, error paths) under valgrind too.
Think of it like this: valgrind is like an auditor who sits beside the cashier and checks every single note that goes in and out of the till. Business is much slower while the auditor is there, but every wrong transaction is written down with the time it happened.
Tip: On Windows, install WSL (Windows Subsystem for Linux) with Ubuntu and run valgrind there; macOS support is limited, so use AddressSanitizer on macOS.

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

Finding memory bugs with valgrind · 1/6

valgrind

In this lesson you will find memory bugs with valgrind.

Prefer a video by a teacher? Find free videos on “valgrind memcheck tutorial memory leak invalid read c” on YouTube ↗

In real life: A leak in a report generator

A school's report-card generator slowly used more memory each term as it processed thousands of students. valgrind showed "definitely lost" blocks allocated in format_grade_line and never freed in the caller. Adding the missing free and re-running valgrind gave "All heap blocks were freed -- no leaks are possible".

output
==9132== HEAP SUMMARY:
==9132==     in use at exit: 0 bytes in 0 blocks
==9132==   total heap usage: 4,812 allocs, 4,812 frees, 391,220 bytes allocated
==9132== All heap blocks were freed -- no leaks are possible

Practice (0/3 done)

Task 1 · Question

valgrind says "Address … is 0 bytes after a block of size 40 alloc'd". What is the most likely bug for an int array of 10?

Task 2 · Question

Which leak category is a definite leak to fix?

Task 3 · Practice

Write a program with: a malloc'd int array read one past the end, a decision based on an uninitialised malloc'd value, a double free, and one leak. Run it under valgrind --leak-check=full, copy the first line of each of the four reports, then fix the bugs one at a time, re-running valgrind after each fix.

Quick quiz

Question 1

1.On which systems does valgrind run best?

Question 2

2.Do you need to rebuild with special flags for valgrind?

Question 3

3.Why fix the first valgrind error first?

Question 4

4.A clean valgrind run proves that…

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

On which systems does valgrind run best?

Answer: Linux (including WSL)

Use WSL on Windows.

Do you need to rebuild with special flags for valgrind?

Answer: No, but -g gives line numbers

It runs the normal binary.

Why fix the first valgrind error first?

Answer: Later errors are often consequences of the first

Corrupted memory causes follow-on errors.

A clean valgrind run proves that…

Answer: No memory errors happened on the paths that this run executed

Untested paths may still have bugs.

Which tool is typically faster: valgrind or AddressSanitizer?Related

Answer: AddressSanitizer

ASan instruments at compile time.

From Memory leaks and other heap bugs

Roughly how much does ASan slow a program down?Related

Answer: About 2×

Much faster than valgrind.

From Sanitizers and warnings

Which is a common memory leak?Related

Answer: A setInterval that is never cleared

The timer and everything its callback refers to stay alive.

From Memory and garbage collection

Who frees heap memory in C?Related

Answer: The program, by calling free

There is no garbage collector.

From Stack and heap

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. 3 more topics in “Debugging and tools” before its exam: Sanitizers and warnings, assert, logging and testing C code, A method for debugging.
  2. Module 11 exam: Debugging and tools · 12 questions · 25 min, without help. 5 topics of this module still to finish first.
  3. Then the next module, Embedded C, system calls and careers. 60 topics left in the course before the final exam.

← Previous: Debugging with gdb