CLion 2025.2 Help

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-pointerfsanitize-recover/fno-sanitize-recover-fsanitize-blacklist 等。

    使用 [-g] 以在警告消息中包含文件名和行号。

    添加优化级别 [-OX] 以获得合理的性能(请参阅特定 Sanitizer 文档中的建议)。

非 CMake 项目的 Sanitizers

调整 Sanitizers 设置

  • 转到 设置 | 构建、执行、部署 | 动态分析工具 | Sanitizers 并设置以下内容:

    Sanitizers 设置
    • 运行时标志

      在本节中,为每个 Sanitizer 指定运行时选项。 您可以手动完成此操作,也可以点击 从现有环境变量导入标志 按钮(如果变量 ASAN/MSAN/LSAN/TSAN_OPTIONS 存在,则此按钮可用)。 请参阅 Sanitizer 通用标志

    • 使用可视化表示 Sanitizer 的输出

      选中此复选框以在预览编辑器和帧信息中显示树状视图输出:

      CLion Sanitizers 可视化输出

      要使可视化输出可用,请切换到至少 Clang 3.8.0 或 GCC 5.0.0。 有关在 CLion 中更改编译器的更多信息,请参阅此 说明

      Sanitizers 视图允许跳转回源代码并将警告数据复制到剪贴板:

      Sanitizers 视图操作

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

      CLion 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 将向您发送通知:

cl_sanitizer_symbolizerwarning.png

AddressSanitizer

AddressSanitizer (ASan) 是一种内存损坏检测器,能够发现以下类型的错误:

  • 堆、栈和全局缓冲区溢出

  • 释放后使用(悬空指针解引用)

  • 超出作用域后使用 -fsanitize-address-use-after-scope

  • 返回后使用(传递 detect_stack_use_after_return=1ASAN_OPTIONS

  • 双重释放,无效释放

  • 初始化顺序错误

例如,请考虑以下代码片段:

int global_array[100] = {-1}; int main(int argc, char **argv) { return global_array[argc + 100]; // global buffer overflow }

使用 -fsanitize=address -fno-omit-frame-pointer -O1 标志构建时,由于 AddressSanitizer 检测到 全局缓冲区溢出 ,该程序将以非零代码退出:

AddressSanitizer

注释 表示 ASan 在检测到的第一个错误时停止。 要更改此行为并使 ASan 在报告第一个错误后继续运行,请将 -fsanitize-recover=address 添加到编译器标志,并将 halt_on_error=false 添加到 ASAN_OPTIONS

在 Windows 上配置 AddressSanitizer

在 Windows 上,您可以使用 MSVC 工具链clang-cl 编译器运行 AddressSanitizer。

  1. 运行 Visual Studio 安装程序 并确保安装 C++ AddressSanitizer 组件。 您可以在 使用 C++ 进行桌面开发 节点下找到它:

    在 Visual Studio 安装程序中选择 AddressSanitizer
  2. 在 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

    带有 clang-cl 的 MSVC 工具链
  3. 在您的 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 所需的库。

  4. 转到 设置 | 构建、执行、部署 | CMake ,创建一个 Release 配置文件 ,并将其设置为默认(将其移动到配置文件列表顶部):

    Release CMake 配置文件
  5. 尝试加载并构建项目。 如果出现链接器错误,请将所有文件从 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

以下代码由于未删除堆分配的对象而导致内存泄漏:

int main(){ int *x = new int(10); return 0; }

LSan 检测并报告了该问题:

LeakSanitizer

ThreadSanitizer

ThreadSanitizer (TSan) 是一种数据竞争检测器。 数据竞争发生在多个线程在没有同步的情况下访问同一内存,并且至少有一个访问是写操作。

请查看以下会产生数据竞争的代码:

#include <pthread.h> #include <stdio.h> int Global; void *Thread1(void *x) { Global++; return NULL; } void *Thread2(void *x) { Global--; return NULL; } int main() { pthread_t t[2]; pthread_create(&t[0], NULL, Thread1, NULL); pthread_create(&t[1], NULL, Thread2, NULL); pthread_join(t[0], NULL); pthread_join(t[1], NULL); }

当您运行使用 -fsanitize=thread -fPIE -pie -g 编译的程序时,TSan 会打印出数据竞争的报告。 有关输出格式的更多信息,请参阅 ThreadSanitizerReportFormat

ThreadSanitizer

UndefinedBehaviourSanitizer

UndefinedBehaviorSanitizer (UBSan) 是一种运行时检查器,用于检测未定义行为,这些行为是任何具有未指定语义的操作的结果,例如除以零、空指针解引用或使用未初始化的非静态变量。

UBSan 捕获了各种未定义行为,请参阅 clang.llvm.org 上的完整列表。 您可以逐一启用检查,或者使用针对检查组的标志 -fsanitize=undefined-fsanitize=integer-fsanitize=nullability

以下代码说明了移位操作未定义结果的情况:

int main() { int i = 2048; i <<= 28; return 0; }

如果您使用 -fsanitize=undefined 标志(或者使用 -fsanitize=shift )编译此代码并运行,尽管 UBSan 发出警告,程序仍会成功完成:

UndefinedBehaviorSanitizer

要使程序因 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 输出:

int main(int argc, char** argv) { int* a = new int[10]; a[5] = 0; if (a[argc]) std::cout << a[3]; return 0; }
MemorySanitizer
最后修改日期: 2025年 9月 26日