asan 可静态链接,需显式加 -static-libasan 并确保链接阶段生效;tsan 不支持静态链接,-static-libtsan 无效且静默降级为动态链接。

静态链接 ASan 时 -fsanitize=address 不生效?检查链接器是否被绕过
Clang/GCC 的 -fsanitize=address 默认走动态链接(依赖 libasan.so),想静态链接必须显式加 -static-libasan。但很多人加了还是失败,根本原因是:链接阶段被构建系统(如 CMake、autotools)或隐式规则覆盖——比如 CMake 默认用 target_link_libraries() 追加动态库,会把 -static-libasan 冲掉。
- 确认编译和链接命令里都出现
-fsanitize=address -static-libasan,不能只在编译阶段加 - CMake 中避免写
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address"),改用target_compile_options(myexe PRIVATE -fsanitize=address)+target_link_options(myexe PRIVATE -fsanitize=address -static-libasan) - 用
nm -C a.out | grep __asan检查符号是否已内联;若看到U __asan_report_load4(U 表示未定义),说明没链上
TSan 静态链接不可行,-static-libtsan 是个假选项
Clang 官方不提供静态版 libtsan,-static-libtsan 编译会静默忽略,最终仍依赖 libtsan.so。这不是配置错误,是设计限制:TSan 需要在运行时 patch 线程创建/销毁路径(如 pthread_create),静态链接会导致 glibc 符号解析冲突,启动即崩溃。
- 尝试
ldd a.out | grep tsan,一定会看到libtsan.so—— 这是正常现象,不是漏配 - 若必须无动态依赖(如嵌入式容器),只能放弃 TSan,改用
-fsanitize=thread+LD_PRELOAD=/path/to/libtsan.so手动加载,但依然需要该 so 文件存在 - ASan 可静态,MSan 可静态,UBSan 可静态,唯独 TSan 和 LSan(依赖 ASan)不行
asan_symbolize 静态链接后失效?符号信息得靠编译器保留
静态链接 ASan 后,崩溃堆栈可能只剩十六进制地址,asan_symbolize 失效。这不是链接问题,而是调试信息被 strip 或编译时未启用符号生成。
- 确保编译加
-g,且链接时不加-s或--strip-all - 验证:
file a.out输出应含with debug_info;readelf -w a.out | head -n5应有 DWARF 段 - 静态链接 ASan 不影响符号表位置,但若用了
-fvisibility=hidden或 LTO(-flto),需额外加-fno-lto或确保 ASan 符号未被优化掉
混合 sanitizer 链接:ASan + UBSan 静态可行,但别碰 TSan
可以同时用 -fsanitize=address,undefined -static-libasan -static-libubsan,UBSan 静态库存在且稳定。但一旦加入 thread,整个链接会退回到动态模式,且不会报错——ld 会悄悄忽略 -static-libtsan 并链接动态版。
- 检查最终二进制:用
nm a.out | grep -E "(__tsan|__asan)",若只有__asan_*有定义而__tsan_*全是U,说明 TSan 未静态进来 - 交叉编译时更危险:宿主机 Clang 的
libtsan.a根本不存在,工具链不会提醒,只会静默降级 - 生产环境建议只选一种 sanitizer 静态链接,调试期再切回动态 TSan
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!









