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.
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"
}$ 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 allocatedAddressSanitizer: 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.
int main(void) {
int arr[5] = {1, 2, 3, 4, 5};
printf("%d\n", arr[10]); // out of bounds — undefined behavior
return 0;
}$ 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 happensWhy 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.