0

0

如何使用Sanitizers(ASan, TSan, UBSan)检测c++运行时错误【高级调试】

裘德小鎮的故事

裘德小鎮的故事

发布时间:2025-12-21 00:34:02

|

899人浏览过

|

来源于php中文网

原创

Sanitizers 是 LLVM/Clang 和 GCC 提供的运行时检测工具,通过插桩实时捕获内存、线程和未定义行为错误;包括 ASan(内存错误)、TSan(数据竞争)、UBSan(未定义行为),需正确编译链接并配置选项以确保精准高效。

如何使用sanitizers(asan, tsan, ubsan)检测c++运行时错误【高级调试】

Sanitizers 是 LLVM/Clang 和 GCC 提供的一组运行时检测工具,能高效捕获 C++ 中常见且隐蔽的内存、线程和未定义行为错误。它们不是静态分析器,而是在程序运行时插桩(instrumentation),通过轻量级内存/指令监控实时报告问题,精度高、开销可控(通常 2–3 倍 slowdown),是现代 C++ 工程调试与 CI 质量门禁的关键手段。

一、快速启用 ASan 检测内存错误

AddressSanitizer(ASan)专用于检测堆缓冲区溢出、use-after-free、use-after-return、内存泄漏(需额外开启)等。

  • 编译时加 -fsanitize=address -g -O1(推荐 -O1:-O2+ 可能触发优化导致误报或漏报;-g 保留调试信息便于定位)
  • 链接时也需带相同 flag(Clang/GCC 自动处理,但显式写更稳妥)
  • 运行时可设置环境变量增强诊断:
    ASAN_OPTIONS=detect_leaks=1:abort_on_error=1:allocator_may_return_null=0
    其中 detect_leaks=1 启用内存泄漏检测(仅对 main 返回后存活的堆内存有效)
  • 示例崩溃输出会明确标出非法访问地址、访问大小、栈回溯及最近的 malloc/free 记录,直接指向 bug 根源

二、用 TSan 揭露数据竞争(Data Race)

ThreadSanitizer(TSan)在多线程环境下动态追踪内存访问的同步关系,精准识别无锁并发中的竞态条件——这类 bug 往往偶发、难复现,TSan 是目前最实用的解决方案。

  • 编译链接均加 -fsanitize=thread -g -O1(注意:TSan 不兼容 ASan/UBSan,不可共用)
  • 必须使用 TSan-aware 的线程库(如 pthread、std::thread),且所有线程创建/同步操作(mutex、atomic、condition_variable)都会被插桩
  • 典型报告包含两个冲突访问的完整调用栈、各自持有/等待的锁状态、访问类型(read/write)、变量名(若符号可用)
  • 避免误报:对已知安全的无锁模式(如 RCULock-free ring buffer),可用 __tsan_acquire/__tsan_release 手动标注同步点

三、启用 UBSan 捕获未定义行为

UndefinedBehaviorSanitizer(UBSan)检查整数溢出、空指针解引用、类型不匹配(如 signed/unsigned shift)、违反 strict aliasing 等 C++ 标准明确定义为“未定义”的操作。

Copy.ai
Copy.ai

Copy.ai 是一个人工智能驱动的文案生成器

下载

立即学习C++免费学习笔记(深入)”;

  • 基础启用:-fsanitize=undefined -g -O2(UBSan 对优化级别更友好,-O2 可接受)
  • 按需启用子检查项更精准(减少开销):
    -fsanitize=signed-integer-overflow,null,shift,alignment,vptr
    例如 vptr 检测虚表指针损坏(对象析构后调用虚函数),shift 捕获非法位移(如右移负数)
  • UBSan 默认崩溃,也可设 UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=0 收集多次违规后退出
  • 注意:部分检查(如 float-cast-overflow)可能影响浮点性能,生产构建慎用

四、实战建议与避坑要点

Sanitizers 强大但需正确集成,否则易失效或干扰调试流程。

  • 始终用 同一编译器版本 编译所有代码(含第三方静态库),混合使用 clang/gcc 或不同版本会导致插桩不一致,引发假阳性或静默失败
  • 第三方库若无源码,优先找已带 Sanitizer 编译的版本;否则用 -fsanitize-blacklist 排除其目标文件(避免符号冲突)
  • CI 中建议分阶段运行:单元测试跑 ASan + UBSan,集成测试跑 TSan(因 TSan 开销最大)
  • 遇到 “heap-use-after-free” 却找不到 free 点?开启 ASAN_OPTIONS=handle_sigill=1:handle_sigbus=1 捕获更多信号异常
  • ASan 报告 “unknown origin”?确保所有相关源文件都参与编译插桩(尤其模板实现、inline 函数),并检查是否遗漏 -fno-omit-frame-pointer(部分旧版需要)

相关专题

更多
css中float用法
css中float用法

css中float属性允许元素脱离文档流并沿其父元素边缘排列,用于创建并排列、对齐文本图像、浮动菜单边栏和重叠元素。想了解更多float的相关内容,可以阅读本专题下面的文章。

559

2024.04.28

C++中int、float和double的区别
C++中int、float和double的区别

本专题整合了c++中int和double的区别,阅读专题下面的文章了解更多详细内容。

99

2025.10.23

c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

231

2023.09.22

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

436

2024.03.01

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

390

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

572

2023.08.10

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

390

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

572

2023.08.10

高德地图升级方法汇总
高德地图升级方法汇总

本专题整合了高德地图升级相关教程,阅读专题下面的文章了解更多详细内容。

43

2026.01.16

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
React 教程
React 教程

共58课时 | 3.7万人学习

Pandas 教程
Pandas 教程

共15课时 | 0.9万人学习

ASP 教程
ASP 教程

共34课时 | 3.7万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号