thecodex.expert · The Codex Family of Knowledge
C

Memory Safety Tools

A buffer overflow or a leaked allocation can compile perfectly and even run without any visible symptom for a long time — these tools are how you actually find out it’s there before it becomes a real production bug.

C17 / C23 Valgrind or AddressSanitizer Last verified:
Canonical Definition

Valgrind's Memcheck tool runs a compiled program inside a simulated CPU, intercepting every memory access to catch leaks, use-after-free, reading uninitialized memory, and buffer overflows — at a genuine, often significant runtime performance cost, since everything is emulated. AddressSanitizer (ASan) takes a different approach: the compiler instruments the code directly at compile time with a -fsanitize=address flag, catching a similar range of bugs with far less runtime overhead than Valgrind, at the cost of needing to recompile the program specifically for that instrumented build.

Valgrind: catching a leak that compiled cleanly

This program compiles and runs with no visible error at all — the leak is completely silent until a tool like Valgrind actually points it out.

Cleaky.c
int main(void) {
    int *data = malloc(100 * sizeof(int));
    data[0] = 42;
    printf("%d\n", data[0]);
    return 0;   // missing free(data) — a real leak, but the program runs "fine"
}
Cterminal
$ gcc -g -o leaky leaky.c
$ valgrind --leak-check=full ./leaky
==12345== HEAP SUMMARY:
==12345==     in use at exit: 400 bytes in 1 blocks
==12345== 400 bytes in 1 blocks are definitely lost in loss record 1 of 1
==12345==    at malloc (leaky.c:2)   // exactly where the leaked memory was allocated

AddressSanitizer: faster, compiler-integrated

ASan catches the exact moment of an out-of-bounds access with a precise stack trace, and typically runs several times faster than the equivalent Valgrind check — the tradeoff is needing a specially-instrumented build rather than running any existing binary unmodified.

Coverflow.c
int main(void) {
    int arr[5] = {1, 2, 3, 4, 5};
    printf("%d\n", arr[10]);   // out of bounds — undefined behavior
    return 0;
}
Cterminal
$ gcc -fsanitize=address -g -o overflow overflow.c
$ ./overflow
==12345==ERROR: AddressSanitizer: stack-buffer-overflow ...
    #0 in main overflow.c:3   // precise line, immediately when it happens

Why running these regularly matters

Both tools catch bugs that compile with zero warnings and often produce no visible symptom under normal testing — the memory corruption might not crash the program until much later, in a completely unrelated part of the code, making it extremely difficult to trace back without one of these tools. Running Memcheck or ASan as a routine part of testing, not just when something visibly breaks, catches these issues while they're still easy to localize.

Sources

1
Valgrind Developers. Valgrind Quick Start, valgrind.org/docs/manual/quick-start.html, and Clang/GCC AddressSanitizer documentation.