应同时作用于编译和链接阶段,推荐使用CMake 3.19+内置变量set(CMAKE_CXX_SANITIZERS "address"),旧版本需手动添加-fsanitize=address到编译和链接选项。

如何在 CMake 中启用 AddressSanitizer(ASan)
直接加编译选项就行,但必须同时作用于编译和链接阶段,否则会链接失败或检测失效。-fsanitize=address 不能只写在 CMAKE_CXX_FLAGS 里,漏掉链接器就白配。
- 推荐方式:用 CMake 内置开关
CMAKE_CXX_SANITIZERS,CMake 3.19+ 原生支持:set(CMAKE_CXX_SANITIZERS "address")
- 老版本 CMake(
- 务必加
-fno-omit-frame-pointer,否则 ASan 报错堆栈会断、定位困难 - 禁用优化(
-O0)不是必须,但-O1及以上可能让部分内存错误逃逸;调试阶段建议先用-O0
如何在 CMake 中启用 ThreadSanitizer(TSan)
TSan 对编译和链接的耦合更紧,且不兼容部分优化和运行时行为,比 ASan 更容易“配了没反应”或直接崩溃。
- 同样优先用
CMAKE_CXX_SANITIZERS:set(CMAKE_CXX_SANITIZERS "thread")
- TSan 要求所有参与线程检测的目标(包括依赖的静态库)都用相同 TSan 编译,混用非 TSan 目标会导致
undefined reference to __tsan_* - 必须关闭
-fomit-frame-pointer(同 ASan),且禁用-funwind-tables或-fasynchronous-unwind-tables—— 否则可能触发 TSan 自身死锁 - 不能和 ASan/MSan/UBSan 同时启用(Clang/GCC 不允许多 sanitizer 共存),
"address;thread"这种写法无效
为什么开启后程序一跑就 crash 或报 symbol not found
大概率是 sanitizer 运行时库没被正确链接进来,或者项目中混入了未 sanitised 的二进制依赖。
- 检查是否所有 target 都继承了 sanitizer 设置:CMake 中用
add_executable或add_library创建的目标,需确保其属性COMPILE_OPTIONS和LINK_OPTIONS包含对应 flag - 第三方静态库(如
.a文件)若没用 TSan/ASan 编译,链接时会缺失符号,比如__asan_init或__tsan_init—— 此时只能自己重编译该库,或换用动态版(前提是它也带 sanitizer 支持) - macOS 上 ASan 需要 Xcode 命令行工具完整安装(
xcode-select --install),仅装 CLT 不够;且默认不支持 TSan(Clang 报thread sanitizer is not supported on this platform) - Linux 下确认
libasan.so/libtsan.so在LD_LIBRARY_PATH中,或已打入 rpath:set_target_properties(your_target PROPERTIES INSTALL_RPATH "$ORIGIN/../lib")
ASan/TSan 编译产物能否用于生产环境
不能。它们不是“开关式调试工具”,而是深度侵入内存访问和线程调度的运行时插桩机制。
立即学习“C++免费学习笔记(深入)”;
- ASan 会让内存开销涨 2–3 倍,速度降 2x+;TSan 更狠,典型吞吐下降 5–15x,且对 false positive 敏感(比如某些原子操作模式会误报 data race)
- sanitizer 运行时会拦截 malloc/free、pthread_create 等关键入口,生产环境部署等于把整套检测逻辑一起上线 —— 既无必要,也极不稳定
- 唯一合理用法:CI 流水线中专设 sanitizer 构建 job,跑单元测试或 fuzzing;本地开发验证问题时临时开启,验证完立刻关掉
- 别试图用
#ifdef ADDRESS_SANITIZER包裹业务逻辑 —— 这些宏只在编译期可见,且 sanitizer 插桩本身不可条件编译



















