Google Sanitizers
Sanitizers 是 Google 设计的用于动态代码分析的开源工具。 CLion 集成了以下 Sanitizers:
AddressSanitizer (ASan)
LeakSanitizer (LSan)
ThreadSanitizer (TSan)
UndefinedBehaviorSanitizer (UBSsan)
MemorySanitizer (MSan)
Sanitizers 从 Clang 3.1 和 GCC 4.8 开始实现。 所有的 Sanitizers 都可用于 Linux x86_64 机器。 您可以在 Windows 10 上使用 clang-cl 和 MSVC 工具链运行 AddressSanitizer。 对于 macOS,支持的 Sanitizers 包括 AddressSanitizer、ThreadSanitizer 和 UndefinedBehaviorSanitizer。
由于 Sanitizers 基于编译器插装,您需要重新构建项目以开始使用这些工具。
配置 Sanitizers
指定编译器标志
调整以下模板行并将其添加到您的 CMakeLists.txt :
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=[sanitizer_name] [additional_options] [-g] [-OX]")对于
[sanitizer_name],请使用以下之一:address 对应 AddressSanitizer
leak 对应 LeakSanitizer
thread 对应 ThreadSanitizer
undefined 对应 UndefinedBehaviorSanitizer(还有其他选项,请参阅 UBSan 部分)
memory 对应 MemorySanitizer
[Additional_flags]是其他编译标志,例如-fno-omit-frame-pointer、fsanitize-recover/fno-sanitize-recover、-fsanitize-blacklist等。使用
[-g]以在警告消息中包含文件名和行号。添加优化级别
[-OX]以获得合理的性能(请参阅特定 Sanitizer 文档中的建议)。
非 CMake 项目的 Sanitizers
如果您正在处理 Makefile 项目或带有 编译数据库的项目,并使用 自定义构建目标 ,请确保同时指定链接器标志和编译器标志。 例如,在 Makefile 和 AddressSanitizer 的情况下:

调整 Sanitizers 设置
转到 并设置以下内容:

运行时标志
在本节中,为每个 Sanitizer 指定运行时选项。 您可以手动完成此操作,也可以点击 从现有环境变量导入标志 按钮(如果变量
ASAN/MSAN/LSAN/TSAN_OPTIONS存在,则此按钮可用)。 请参阅 Sanitizer 通用标志。使用可视化表示 Sanitizer 的输出
选中此复选框以在预览编辑器和帧信息中显示树状视图输出:

要使可视化输出可用,请切换到至少 Clang 3.8.0 或 GCC 5.0.0。 有关在 CLion 中更改编译器的更多信息,请参阅此 说明。
Sanitizers 视图允许跳转回源代码并将警告数据复制到剪贴板:

当取消选中可视化表示复选框或编译器不符合要求时,Sanitizers 的输出以纯文本形式呈现:

提供 llvm-symbolizer 的路径
为了让 Sanitizers 将地址转换为源代码位置并使堆栈跟踪易于理解,请确保 PATH 或 *SAN_SYMBOLIZER_PATH 环境变量包含 llvm-symbolizer 的位置。
使用以下选项之一:
将 llvm-symbolizer 目录的路径(例如 /usr/bin/ )添加到 系统 PATH。
在运行/调试配置的 环境变量字段中,添加指向特定二进制文件(如 /usr/bin/llvm-symbolizer )的 *SAN_SYMBOLIZER_PATH 。
如果使用 Clang 编译器,而 PATH 或 *SAN_SYMBOLIZER_PATH 变量均未指向 llvm-symbolizer ,CLion 将向您发送通知:

AddressSanitizer
AddressSanitizer (ASan) 是一种内存损坏检测器,能够发现以下类型的错误:
堆、栈和全局缓冲区溢出
释放后使用(悬空指针解引用)
超出作用域后使用
-fsanitize-address-use-after-scope返回后使用(传递
detect_stack_use_after_return=1到ASAN_OPTIONS)双重释放,无效释放
初始化顺序错误
例如,请考虑以下代码片段:
使用 -fsanitize=address -fno-omit-frame-pointer -O1 标志构建时,由于 AddressSanitizer 检测到 全局缓冲区溢出 ,该程序将以非零代码退出:

注释 表示 ASan 在检测到的第一个错误时停止。 要更改此行为并使 ASan 在报告第一个错误后继续运行,请将 -fsanitize-recover=address 添加到编译器标志,并将 halt_on_error=false 添加到 ASAN_OPTIONS。
在 Windows 上配置 AddressSanitizer
在 Windows 上,您可以使用 MSVC 工具链 和 clang-cl 编译器运行 AddressSanitizer。
运行 Visual Studio 安装程序 并确保安装 C++ AddressSanitizer 组件。 您可以在 使用 C++ 进行桌面开发 节点下找到它:

在 CLion 中,转到 并创建一个新的 Visual Studio 工具链或编辑现有工具链。
将 架构 设置为 x86_amd64。
在 C 编译器 和 C++ 编译器 字段中设置 clang-cl 的路径。
您可以使用来自 LLVM 分发版或 Visual Studio 工具的 clang-cl。 在后一种情况下,路径将是,例如, C:\Program Files(x86)\Microsoft Visual Studio\2019\Community\VC\Tools\Llvm\bin\clang-cl.exe 。

在您的 CMakeLists.txt 中,在
add_executable命令之后添加以下行(用您的可执行文件名称替换exec):target_compile_options(exec PRIVATE -fsanitize=address) target_link_directories(exec PRIVATE "$ENV{ProgramFiles\(x86\)}/Microsoft Visual Studio/2019/Professional/VC/Tools/Llvm/x64/lib/clang/10.0.0/lib/windows") target_link_libraries(exec PRIVATE clang_rt.asan_dynamic-x86_64 clang_rt.asan_dynamic_runtime_thunk-x86_64) target_link_options(exec PRIVATE /wholearchive:clang_rt.asan_dynamic_runtime_thunk-x86_64.lib)根据需要调整 ProgramFiles\(x86\)}/Microsoft Visual Studio/2019/Professional/VC/Tools/Llvm/x64/lib/clang/10.0.0/lib/windows 路径。 此目录包含 AddressSanitizer 所需的库。
转到 ,创建一个 Release 配置文件 ,并将其设置为默认(将其移动到配置文件列表顶部):

尝试加载并构建项目。 如果出现链接器错误,请将所有文件从 ProgramFiles\(x86\)}/Microsoft Visual Studio/2019/Professional/VC/Tools/Llvm/x64/lib/clang/10.0.0/lib/windows 复制到 cmake-构建-release 文件夹中。
LeakSanitizer
LeakSanitizer (LSan) 是一种内存泄漏检测器。 在独立模式下,此 Sanitizer 是一种运行时工具,不需要编译器插装。 然而,LSan 也集成到 AddressSanitizer 中,因此您可以将它们结合使用以同时检测内存错误和泄漏。
要将 LeakSanitizer 作为 AddressSanitizer 的一部分启用,请将 detect_leaks=1 传递给 ASAN_OPTIONS 变量。 要运行没有泄漏检测的 ASan 插装程序,请设置 detect_leaks=0。
要仅运行 LSan(并避免 ASan 的性能下降),请使用 -fsanitize=leak 替代 -fsanitize=address。
以下代码由于未删除堆分配的对象而导致内存泄漏:
LSan 检测并报告了该问题:

ThreadSanitizer
ThreadSanitizer (TSan) 是一种数据竞争检测器。 数据竞争发生在多个线程在没有同步的情况下访问同一内存,并且至少有一个访问是写操作。
请查看以下会产生数据竞争的代码:
当您运行使用 -fsanitize=thread -fPIE -pie -g 编译的程序时,TSan 会打印出数据竞争的报告。 有关输出格式的更多信息,请参阅 ThreadSanitizerReportFormat。

UndefinedBehaviourSanitizer
UndefinedBehaviorSanitizer (UBSan) 是一种运行时检查器,用于检测未定义行为,这些行为是任何具有未指定语义的操作的结果,例如除以零、空指针解引用或使用未初始化的非静态变量。
UBSan 捕获了各种未定义行为,请参阅 clang.llvm.org 上的完整列表。 您可以逐一启用检查,或者使用针对检查组的标志 -fsanitize=undefined、 -fsanitize=integer 和 -fsanitize=nullability。
以下代码说明了移位操作未定义结果的情况:
如果您使用 -fsanitize=undefined 标志(或者使用 -fsanitize=shift )编译此代码并运行,尽管 UBSan 发出警告,程序仍会成功完成:

要使程序因 UBSan 的诊断而退出,请使用 -fno-sanitize-recover 选项。
MemorySanitizer
MemorySanitizer (MSan) 是一种未初始化内存读取检测器。 此 Sanitizer 检测堆栈或堆分配的内存在写入之前被读取的情况。 MSan 还能够跟踪位域中未初始化的位。
MSan 可以追溯未初始化值的来源到其创建位置并报告此信息。 传递 -fsanitize-memory-track-origins 标志以启用此功能。
要高效使用 MSan,请使用 -fsanitize=memory -fPIE -pie -fno-omit-frame-pointer -g 编译您的程序,添加 -fno-optimize-sibling-calls 和 -O1 或更高版本。
以下是包含未初始化读取的代码示例及相应的 MSan 输出:
