addresssanitizer(asan)是clang/gcc内置的编译期内存检测工具,可精准定位数组越界、堆栈溢出、释放后使用等错误,配合redzone拦截和valgrind memcheck可覆盖更多未定义行为场景。

用 AddressSanitizer 快速捕获越界读写
AddressSanitizer(ASan)是 Clang 和 GCC 内置的内存错误检测器,能实时发现数组越界、栈/堆缓冲区溢出、释放后使用等行为。它不是运行时库替换,而是编译期插桩,开销约 2×,但足够用于开发和测试阶段。
常见错误现象:SEGV 信号崩溃但无明确位置、malloc(): corrupted unsorted chunks、值莫名被改写——这些往往就是越界导致的间接破坏,ASan 能直接定位到越界那行代码。
- Clang 编译:加
-fsanitize=address -g,例如clang++ -fsanitize=address -g main.cpp -o main - GCC 编译(≥4.8):同样用
-fsanitize=address -g,注意需链接 libasan(通常自动处理) - 运行时报错会显示完整调用栈、越界类型(
heap-buffer-overflow/stack-buffer-underflow)、访问偏移量和对象布局,比如:READ of size 4 at 0x60200000001c thread T0 - 禁用部分检查(如仅关注越界不查 UAF)可用
-fsanitize=address -mllvm -asan-stack=1 -mllvm -asan-global=1,但不推荐初用者调整
手动 hook new/delete 捕获堆越界可疑操作
ASan 对静态数组或结构体内嵌数组越界(如 struct { int arr[10]; } s; s.arr[15] = 1;)有时不报,因为未触发插桩内存边界。此时可配合轻量级分配器拦截做辅助验证。
核心思路:重载全局 operator new 和 operator delete,在分配块前后各加 8–16 字节 redzone,并用 mprotect(Linux/macOS)或 VirtualProtect(Windows)设为不可访问页。越界访问 redzone 会触发 SEGV,再结合 sigaction 捕获信号并打印调用栈。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- redzone 大小必须对齐页边界(通常 4096 字节),否则
mprotect失败 - 不要在信号处理函数里调用
malloc、printf等非异步信号安全函数;改用write+backtrace+backtrace_symbols_fd - 注意 STL 容器(如
std::vector)内部可能绕过new直接调用malloc,需同时拦截malloc/free才完整
用 valgrind memcheck 做补充验证(尤其针对 ASan 不覆盖场景)
Valgrind 的 memcheck 工具不依赖编译选项,纯运行时分析,对栈上越界(如局部数组)、未初始化读取、跨平台一致性检查更稳,但性能极慢(10–30×),只适合单测或回归验证。
典型使用场景:ASan 没报但程序行为异常;怀疑是未定义行为引发的随机崩溃;需要确认是否所有路径都经过了越界检查。
- 运行命令:
valgrind --tool=memcheck --leak-check=full --track-origins=yes ./main - 关键输出字段:
Invalid write of size X后紧跟地址、偏移、所在函数及源码行号;Address 0x... is 12 bytes inside a block of size 40 alloc'd明确提示越界量 - 注意:valgrind 不支持某些 SIMD 指令或内联汇编,遇到
Syscall param write(buf) points to unaddressable byte(s)需结合源码判断是否误报 - macOS 上 valgrind 不可用,此时只能依赖 ASan + 自定义 redzone 或
ubsan(-fsanitize=undefined)补位
为什么不能只靠断言或 size_t 检查?
运行时断言(如 assert(i )只防逻辑错误,不防指针算术越界(<code>ptr + 100)、类型混淆(reinterpret_cast 后越界)、或编译器优化引入的 UB。而 size_t 是无符号类型,减法溢出会导致极大正数,if (i >= size) 判断反而失效。
- 例如:
size_t i = 0; if (i - 1 永真,因为 <code>i - 1是极大值 - ASan/redzone 是唯一能在**实际访存瞬间**捕获硬件级越界的手段,不依赖程序员是否写了判断
- CI 流程中建议强制开启 ASan 编译 + 运行最小测试集,比人工 code review 更可靠
越界监控真正难的不是加开关,而是让所有构建环境(包括第三方静态库)都启用 ASan,否则插桩不完整就会漏检。别忘了检查你链接的 .a 文件是否也用 -fsanitize=address 编译过。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










