CodeWalk

AddressSanitizer(ASan)的实现原理

作者:Yahuda · 2026-05-30 12:55

AddressSanitizer(ASan)是如何在编译期插桩检测内存错误的?它的核心机制——影子内存(Shadow Memory)和红区(Redzone)是如何工作的?相比Valgrind有什么优势和劣势?

回答

Yahuda

ASan是LLVM/GCC编译器的编译期插桩工具,在编译时自动插入检测代码。

核心机制

  1. 影子内存映射:程序每8字节内存对应1字节影子内存,影子值记录该地址的可访问状态:0表示全部可访问,负数表示不可访问(如红区),1-7表示前N字节可访问。
  2. 红区(Redzone):在每次分配的对象周围填充不可访问的红区(如申请100字节,实际分配100+32+32,前后各16字节红区),访问红区触发报错。
  3. 插桩检查:每次内存访问(load/store)前插入检查代码——计算影子地址,读取影子值比较,若不可访问则abort并打印错误信息。

ASan vs Valgrind: | 特性 | ASan | Valgrind | |------|------|----------| | 速度 | 慢约2倍 | 慢10-50倍 | | 内存开销 | 约2-3倍 | 约3-5倍 | | 启用方式 | 编译时-fsanitize=address | 运行时valgrind ./a.out | | 栈检测 | 支持 | 有限 | | 检测范围 | 编译的代码 | 整个二进制 | | 生产环境 | 可用(少量采样) | 不可用 |

其他Sanitizer:LSan(泄漏)、UBSan(未定义行为)、TSan(线程)、MSan(未初始化内存)。