解决Sanitizer 已知问题和限制

注意

请就你希望在未来版本中看到的内容向我们发送反馈,如果遇到问题,请报告 bug

不兼容的选项和功能

以下选项和功能不兼容 /fsanitize=address ,应禁用或避免。

标准库支持

MSVC 标准库 (STL) 部分使用 AddressSanitizer 并提供其他代码安全检查。 有关详细信息,请参阅 container-overflow 错误

禁用批注或不支持注释的标准库版本中时,STL 代码中引发的 AddressSanitizer 异常仍会识别实际 bug。 但是,如果启用了批注,并且使用支持它们的标准库版本,则它们更精确。

此示例演示了精准率的缺失和启用注释的好处:

// Compile with: cl /fsanitize=address /Zi
#include <vector>

int main() {   
    // Create a vector of size 10, but with a capacity of 20.    
    std::vector<int> v(10);
    v.reserve(20);

    // In versions prior to 17.2, MSVC ASan does NOT raise an exception here.
    // While this is an out-of-bounds write to 'v', MSVC ASan
    // ensures the write is within the heap allocation size (20).
    // With 17.2 and later, MSVC ASan will raise a 'container-overflow' exception:
    // ==18364==ERROR: AddressSanitizer: container-overflow on address 0x1263cb8a0048 at pc 0x7ff6466411ab bp 0x005cf81ef7b0 sp 0x005cf81ef7b8
    v[10] = 1;

    // Regardless of version, MSVC ASan DOES raise an exception here, as this write
    // is out of bounds from the heap allocation.
    v[20] = 1;
}

重写运算符 new 和 delete

AddressSanitizer (ASAN) 使用自定义版本的 operator newoperator delete 查找分配错误,例如 alloc_dealloc_mismatch。 使用 /INFERASANLIBS 运行链接器可确保 ASAN 的 new/delete 替代优先级较低,以便链接器选择其他库中的任何 operator newoperator delete 替代,而 ASAN 的自定义版本。 发生这种情况时,ASAN 可能无法捕获依赖于其自定义 operator newoperator delete的某些错误。

MFC 包括自定义 operator new 替代, operator delete 并可能错过错误,例如 alloc_dealloc_mismatch

内存使用率

AddressSanitizer 运行时在执行期间不会将内存释放回 OS。 从 OS 的角度来看,看似存在内存泄漏。 这是有意的,以便内存并非全部提前分配。

AddressSanitizer 运行时 DLL 位置

clang_rt.asan*.dll 运行时文件安装在 %VSINSTALLDIR%\VC\Tools\MSVC\<version>\bin\<host-arch>\<target-arch>\ 中编译器旁边。 这些位置位于调试会话和 Visual Studio 开发人员命令提示符的路径上。 这些文件绝不会放在 C:\Windows\System32C:\Windows\SysWOW64 中。

自定义属性表支持

Visual Studio 属性管理器窗口允许向项目添加自定义 .props 文件。 即使显示了“启用地址清理器”属性(),但版本仍不支持。<EnableASAN> 这是因为自定义 .props 文件包含在之后 Microsoft.cpp.props,后者使用 <EnableASAN> 该值设置其他属性。

解决方法是,在项目的根目录中创建一个 Directory.Build.props 文件来定义 <EnableASAN> 属性。 有关详细信息,请参阅自定义 C++ 生成

线程局部变量

线程局部变量(使用 __declspec(thread) 或声明的 thread_local全局变量)不受 AddressSanitizer 的保护。 此限制不特定于 Windows 或 Microsoft Visual C++,而是一般限制。

部分清理的可执行文件的问题

如果进程中的所有代码未使用 /fsanitize=address编译,ASan 可能无法诊断所有内存安全错误。 最常见的示例是使用 ASan 编译 DLL,但加载到包含未使用 ASan 编译的代码的进程中。 在这种情况下,ASan 尝试对 ASan 初始化之前发生的分配进行分类。 重新分配这些分配后,ASan 会尝试拥有并监视内存的生存期。

如果在进程结束之前从进程卸载了使用 ASan 编译的所有 DLL,则由于对截获的函数(例如memcmpmemcpymemmove等)的悬而未决的引用可能会崩溃。 为了获得最佳结果,请使用 编译测试 /fsanitize=address中的所有模块,或者不要卸载使用 ASan 编译的模块,然后进入该过程。

请向 开发人员社区报告任何 bug。

另请参阅

AddressSanitizer 概述
AddressSanitizer 生成和语言参考
AddressSanitizer 运行时参考
AddressSanitizer 阴影字节
AddressSanitizer 云或分布式测试
AddressSanitizer 调试程序集成
AddressSanitizer 错误示例