Catching Memory Corruption with LLVM AddressSanitizer
Learn how LLVM's AddressSanitizer uses shadow memory and redzones to turn silent memory corruption into immediate, actionable crash reports in C/C++.
02 Sept 2025, 06:43 UTC

The Invisible Crash: Why Memory Errors are Hard to Debug
In C and C++, a buffer overflow or a use-after-free bug rarely crashes a program exactly where the error occurs. Instead, these bugs corrupt the heap or stack silently, leading to a "heisenbug"—a crash that happens thousands of instructions later in a completely unrelated part of the code. By the time the program segfaults, the evidence of the original corruption is gone.
The solution is AddressSanitizer (ASan). Rather than waiting for a crash, ASan turns memory corruption into an immediate, loud failure at the exact moment the illegal access happens. It achieves this through a combination of compiler instrumentation and a specialized runtime library.
How ASan Tracks Memory State
ASan does not simply wrap pointers; it monitors the validity of every byte of memory using a technique called shadow memory. A small portion of the virtual address space is reserved as a map. Every 8 bytes of application memory are mapped to 1 byte of shadow memory.
- Clean Memory: If the shadow byte is 0, the corresponding 8 bytes of application memory are fully accessible.
- Poisoned Memory: If the shadow byte is non-zero, it indicates a "redzone"—a forbidden area.
The compiler inserts checks before every load and store. If the code attempts to access a poisoned region, the ASan runtime intercepts the operation and prints a detailed diagnostic report before the program continues and corrupts further state.
Redzones and Quarantines
To catch overflows, ASan surrounds stack and global objects with redzones—small blocks of poisoned memory. If an index goes one byte past the end of an array, it hits the redzone and triggers an alert.
To catch use-after-free errors, the ASan runtime intercepts free() and delete. Instead of returning the memory to the OS immediately, it places the memory in a quarantine. The memory is marked as poisoned, so any subsequent attempt to read or write to that pointer will be detected as a use-after-free, even if the allocator hasn't officially reused that block yet.
Practical Implementation: Detecting a Heap Overflow
To use ASan, you must compile and link your code with the -fsanitize=address flag. It is highly recommended to include -g to ensure the resulting report includes file names and line numbers.
Example Scenario
Consider a simple program that writes past the end of a heap-allocated buffer:
// main.c
#include <stdlib.h>
#include <string.h>
int main() {
char *buf = malloc(8);
// Intentional overflow: writing 12 bytes into an 8-byte buffer
memset(buf, 0, 12);
free(buf);
return 0;
}
Compilation and Execution
Run the following command in your terminal using Clang (ensure you have the LLVM toolchain installed):
clang -fsanitize=address -g main.c -o asan_demo
Run the binary as a standard user:
./asan_demo
Expected Result
Instead of completing silently or crashing randomly, the program will terminate immediately with a report stating heap-buffer-overflow. The report will identify the exact line of the memset call and provide the stack trace for where the memory was originally allocated via malloc.
Trade-offs and Limitations
ASan is a powerful tool, but it is not a "silver bullet" for all memory issues. Engineers should be aware of the following constraints:
| Constraint | Impact | Mitigation |
|---|---|---|
| CPU/RAM Overhead | Typically 2x slowdown and increased memory usage. | Use ASan during testing/CI, not in production. |
| Memory Leaks | ASan focuses on corruption, not leaks. | Use LeakSanitizer (LSan) or Valgrind. |
| Custom Allocators | Memory pools may hide overflows from ASan. | Use __asan_poison_memory_region to manually mark boundaries. |
| Partial Instrumentation | Uninstrumented libraries can cause false negatives. | Recompile all dependencies with -fsanitize=address. |
Verification and Rollback
To verify that ASan is active in a binary, you can check the linked libraries using ldd (on Linux) or otool -L (on macOS). You should see a reference to the ASan runtime library.
Rollback: Because ASan is a compile-time instrumentation, there is no state to "roll back" in the environment. To remove ASan, simply recompile the project without the -fsanitize=address flag.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.