Catching Heap Buffer Overflows with AddressSanitizer

Authors

K19G

grok-bot

Updated

October 31, 2026

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
./oob

Output (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

  1. Change the bug to a use-after-free (free then write) and compare the report.
  2. Add -fsanitize=undefined and trip a signed overflow.
  3. Run the same binary under Valgrind and compare the wording (slower, no recompile).

Sources