valgrind: Usage, Options & Common CI Errors
valgrind runs a program under instrumentation to catch memory bugs and leaks.
valgrind (Memcheck) finds invalid reads/writes, uninitialized values, and leaks. The single most important CI flag is --error-exitcode: without it, valgrind reports errors but still exits 0, so the job passes despite real bugs.
What it does
valgrind runs a program on a synthetic CPU and instruments memory operations. Its default tool, Memcheck, detects invalid memory access, use of uninitialized memory, double frees, and memory leaks, reporting each with a stack trace.
Common usage
valgrind --leak-check=full --error-exitcode=1 ./app
valgrind --leak-check=full --show-leak-kinds=all ./app
valgrind --track-origins=yes ./app # where uninit came from
valgrind --suppressions=known.supp ./app
valgrind --tool=helgrind ./app # data-race detectorOptions
| Flag | What it does |
|---|---|
| --leak-check=full | Detailed per-leak reporting |
| --error-exitcode=N | Exit N if any error is found (CI gate) |
| --track-origins=yes | Trace uninitialized-value origins |
| --show-leak-kinds=all | Report all leak categories |
| --suppressions=<file> | Ignore known/false-positive errors |
| --tool=memcheck|helgrind|callgrind | Choose the analysis tool |
Common errors in CI
The silent trap: by default valgrind exits 0 even when it finds errors, so a leaky build "passes" - always add --error-exitcode=1 to gate CI. In containers valgrind may hit "Fatal error ... could not create temp dir" or fail under a restrictive seccomp profile (it needs to mmap and intercept syscalls; loosen seccomp). It also runs ~10-50x slower, so wrap long suites in timeout. Use --gen-suppressions=all to capture and then suppress library false positives.