AddressSanitizer必须显式加-fsanitize=address且推荐-O0,否则不注入检测逻辑;它可靠捕获堆越界和部分栈越界,但禁用优化、避免LD_PRELOAD干扰、链接选项需同步。

AddressSanitizer 编译时必须加 -fsanitize=address 且禁用优化
不加这个编译选项,ASan 根本不会注入检测逻辑,代码跑得再错也静默。常见错误是只加了 -g 或 -O0 就以为够了。必须显式开启:g++ -fsanitize=address -g -O0 file.cpp -o prog。-O0 很关键——ASan 在 -O1 及以上可能因指令重排或寄存器优化漏掉某些栈越界(尤其是局部数组的尾后读);-g 不是必须但强烈建议,否则报错时看不到行号。
堆越界(new/malloc)和栈越界(局部数组)都能捕获,但行为有差异
ASan 对堆分配(new、malloc)的越界访问检测非常可靠,包括 delete 后使用、malloc 返回指针的前后一字节越界等。栈上则要注意:它只检测「连续栈帧内」的越界,比如 int a[4]; a[5] = 1; 能报;但若越界写入刚好落在下一个局部变量的起始地址(未跨栈帧),可能被优化掩盖或漏报。另外,std::vector 的 operator[] 不做边界检查,ASan 能抓到它的底层数据指针越界,但 .at() 抛异常属于运行时逻辑,ASan 不管。
运行时报错信息里 READ/WRITE of size X 是关键线索
典型输出如:ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60200000001c at pc 0x000000401234 bp 0x7fff12345678 sp 0x7fff12345660,后面会跟 READ of size 4 或 WRITE of size 1。这个 size 值很重要:它告诉你程序实际读/写了几个字节,结合指针类型能反推是否是 int* 解引用越界还是 char* 偏移错了。如果看到 size 1 却在操作 int,大概率是类型转换丢失了宽度信息,比如 (char*)ptr + 4 然后解引用成 int——ASan 按 char* 的粒度标记内存,但读取按 int 发生,就容易误判或漏报。
不能和 UBSan 或 ThreadSanitizer 混用,且 LD_PRELOAD 会干扰
多个 sanitizer 同时启用(比如 -fsanitize=address,undefined)在 GCC/Clang 多数版本中会导致链接失败或运行时崩溃,官方明确不支持组合。另外,如果程序依赖 LD_PRELOAD 加载自定义 .so(比如某些 hook 库),ASan 的内存拦截机制可能被绕过,越界访问不报错。调试时务必确认环境干净:unset LD_PRELOAD 再运行。还有个小坑:CMake 用户容易在 CMAKE_CXX_FLAGS 里加了 ASan,却忘了给 CMAKE_EXE_LINKER_FLAGS 也加同样选项,导致链接阶段没注入 runtime,运行时报 undefined symbol: __asan_init。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











