Detecting Errors: ASan, Valgrind, Static Analyzers
What This Concept Is
Three families of tools turn invisible memory bugs into readable reports:
- Compiler sanitizers:
-fsanitize=address(ASan),-fsanitize=undefined(UBSan), and-fsanitize=leak(LSan). Instrument the binary at compile time. Fast (~2x slower) and precise. You rebuild your program with sanitizers and run it normally. - Valgrind: a dynamic binary-translation tool with Memcheck as its default. No recompile needed; very slow (~20x); catches uninitialized reads, invalid frees, and leaks at tiny-value precision.
- Static analyzers:
clang -fanalyze,cppcheck,Coverity, the-Wanalyzer-*family in GCC. No run; they inspect the source for suspicious patterns. Zero runtime cost but false positives and blind spots.
The three complement each other; none is a full replacement.
Why It Matters Here
Most of the bugs in Cluster 4 (overflows, UAF, double-free, leaks) are invisible until you weaponize the compiler and runtime against them. In practice this means every C project has CI jobs that run the test suite once under -fsanitize=address,undefined and once under Valgrind, and runs a static analyzer on every pull request.
Concrete Example
Buggy program:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int *a = malloc(4 * sizeof *a);
for (int i = 0; i <= 4; i++) a[i] = i; /* OOB at i = 4 */
int *leak = malloc(16); /* never freed */
(void)leak;
printf("%d\n", a[0]);
free(a);
return 0;
}
Three different views:
$ gcc -Wall -Wextra -g -O1 -fsanitize=address,undefined -o bug bug.c && ./bug
==12345==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x... at pc ...
WRITE of size 4 at 0x...
#0 in main bug.c:6
$ gcc -Wall -Wextra -g -O1 -o bug bug.c && valgrind --leak-check=full ./bug
Invalid write of size 4
at ... main (bug.c:6)
...
LEAK SUMMARY:
definitely lost: 16 bytes in 1 blocks
$ clang --analyze -Xanalyzer -analyzer-output=text bug.c
bug.c:6:29: warning: Out of bound memory access [core.ArrayBound]
bug.c:7:18: warning: Potential leak of memory pointed to by 'leak' [unix.Malloc]
Each tool finds both bugs with different style and different strengths.
Common Confusion / Misconception
"ASan is the same as Valgrind." They overlap but are not the same. ASan requires a recompile and catches stack and global overflows that Valgrind (which works on unmodified binaries) cannot see. Valgrind catches uninitialized reads more precisely.
"A green ASan run means my program is safe." ASan only sees bugs that execute on the tested inputs. Coverage-guided fuzzers plus sanitizers is the combined recipe.
"Static analyzers are for managers." Used well, a project-wide analyzer replaces hundreds of code-review catches per year. Used poorly (every warning disabled), it does nothing.
How To Use It
In every C project:
- Add a CI job:
gcc -Wall -Wextra -Werror -fsanitize=address,undefined -g -O1. - Add a second CI job running the same tests under
valgrind --error-exitcode=1 --leak-check=full. - Add a static-analysis job:
clang --analyzeon each file, orcppcheck --enable=all --error-exitcode=1. - When a sanitizer reports a bug, fix it the same day. Do not suppress until you have a ticket explaining why.
Check Yourself
- Name one bug class each of the three tool families can catch, and one class each struggles with.
- Why does ASan need a recompile while Valgrind does not?
- Why is
-fsanitize=addressusually incompatible with running insidevalgrind?
Mini Drill or Application
Take the use-after-free program from concept 11 and run it through all three tool families. Record:
- the ASan command line and full error output
- the
valgrindcommand line and its output - the
clang --analyzeorcppcheckoutput on the same source
Add -Wall -Wextra compilation warnings as a fourth view. Note which tools catch the bug and which do not. Fix the bug; rerun all tools; they should all be quiet.
Read This Only If Stuck
- AddressSanitizer documentation (LLVM)
- UndefinedBehaviorSanitizer documentation (LLVM)
- Valgrind Memcheck manual
- Clang Static Analyzer
- GCC
-fanalyzerdocumentation
Source Backbone
This systems page should stay anchored in the local C and computer-organization sources.
- The C Programming Language - canonical C pointer and memory model source.
- Computer Organization and Design - machine representation and hardware support.
- CODE - first-principles representation support.