Catching Heap Buffer Overflows with AddressSanitizer
Catching Heap Buffer Overflows with AddressSanitizer
Thesis
AddressSanitizer (ASan) turns silent memory corruption into a loud, actionable report. You compile with -fsanitize=address, keep frame pointers, and run the binary — redzones around heap objects catch overflows that MPX-style hardware bounds checks often missed in practice. This chapter deliberately overflows a four-int allocation and reads the report.
Mental model
malloc(16) → [redzone][ 16 bytes ][redzone]
▲
p[4] write lands in redzone → ASan trap
| Flag | Why |
|---|---|
-fsanitize=address |
Link the runtime and instrument loads/stores |
-fno-omit-frame-pointer |
Readable stacks in reports |
-O0 or -O1 |
Keep the bug visible; -O2 can elide dead stores |
Intel MPX tried hardware bounds tables; it was removed from Linux and GCC because of cost and incomplete coverage. ASan stays the boring CI default for C/C++ memory bugs.
Worked examples
Verified with gcc + libasan.so.8 on Linux/amd64.
Case 1: heap buffer overflow
// oob.c
#include <stdlib.h>
#include <stdio.h>
int main(void) {
volatile int *p = (volatile int *)malloc(4 * sizeof(int));
if (!p) return 1;
p[4] = 42; /* deliberate OOB write */
printf("survived? %d\n", p[0]);
free((void *)p);
return 0;
}cc -O0 -g -fsanitize=address -fno-omit-frame-pointer -o oob oob.c
./oobOutput (trimmed) from this run:
=================================================================
==925605==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x502000000020 at pc 0x56146392321f bp 0x7ffdfeabc7b0 sp 0x7ffdfeabc7a8
WRITE of size 4 at 0x502000000020 thread T0
#0 0x56146392321e in main /home/box/agent-data/books-scout/runs/2026-10-27-oneshot/labs/c-asan/oob.c:6
#1 0x7fc3da035ca7 (/lib/x86_64-linux-gnu/libc.so.6+0x29ca7) (BuildId: 5e5b51f4c39af9ac589408c1dc432ba390a273cc)
#2 0x7fc3da035d64 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29d64) (BuildId: 5e5b51f4c39af9ac589408c1dc432ba390a273cc)
#3 0x5614639230f0 in _start (/home/box/sand-data/books-scout/runs/2026-10-27-oneshot/labs/c-asan/oob+0x10f0) (BuildId: 48da982878501a3ff9e6e587f13a1311f8552983)
0x502000000020 is located 0 bytes after 16-byte region [0x502000000010,0x502000000020)
allocated by thread T0 here:
#0 0x7fc3da2f4c57 in malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:69
#1 0x5614639231ca in main /home/box/agent-data/books-scout/runs/2026-10-27-oneshot/labs/c-asan/oob.c:4
#2 0x7fc3da035ca7 (/lib/x86_64-linux-gnu/libc.so.6+0x29ca7) (BuildId: 5e5b51f4c39af9ac589408c1dc432ba390a273cc)
SUMMARY: AddressSanitizer: heap-buffer-overflow /home/box/agent-data/books-scout/runs/2026-10-27-oneshot/labs/c-asan/oob.c:6 in main
Shadow bytes around the buggy address:
0x501ffffffd80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x501ffffffe00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Exit status was 1. The report names the exact line of the write and the malloc site.
Trap
Shipping ASan builds to production. The runtime is for tests and fuzzing. It enlarges memory and slows code. Keep it on in CI and in canary fuzz jobs; strip it from release binaries.
Boring rule
Every C PR that touches unsafe buffers gets an ASan (and preferably UBSan) CI job. Reproduce with a 10-line file before arguing about “theoretical” bugs.
Try this
- Change the bug to a use-after-free (
freethen write) and compare the report. - Add
-fsanitize=undefinedand trip a signed overflow. - Run the same binary under Valgrind and compare the wording (slower, no recompile).
Sources
- AddressSanitizer wiki (Google)
- GCC instrumentation options
- MPX removal notes in kernel/GCC mailing lists (historical contrast)