不兼容的选项和功能
以下选项和功能不兼容 /fsanitize=address ,应禁用或避免。
-
/RTC选项与 AddressSanitizer 不兼容,应禁用。 - 增量链接不受支持,应禁用。
- Edit-and-Continue 不受支持,应禁用。
- 协同例程与 AddressSanitizer 不兼容,且可恢复函数不在检测范围内。
- OpenMP 不受支持,应禁用。
- 托管 C++ 不受完全支持,应禁用。 有关详细信息 ,请参阅编译器警告(级别 1) C5089 。
- C++ AMP 不受支持,应禁用。
- 通用 Windows 平台 (UWP) 应用程序不受支持。
- 特殊情况列表文件不受支持。
-
未生成
/fsanitize=address预编译标头不受支持。
标准库支持
Microsoft Visual C++ (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;
}
重写 operator new 和 delete
AddressSanitizer (ASan) 使用自定义版本的 operator new 和 operator delete 查找分配错误,例如 alloc_dealloc_mismatch。 运行链接器/INFERASANLIBS以确保 ASan 的new/delete替代优先级较低,以便链接器在其他库中选择operator new或operator delete替代 ASan 的自定义版本。 发生这种情况时,ASan 可能不会捕获依赖于其自定义 operator new 和 operator delete的一些错误。
MFC 包括用于 operator new 和 operator delete的自定义重写。 使用Microsoft基础类(MFC)替代而不是提供的 operator newoperator deleteASan 时,ASan 可能会完全错过错误,或者因此错误地对其进行分类。 可能会错过以下错误或错误分类:
alloc_dealloc_mismatchdouble-freeheap-use-after-freeheap-buffer-overflownew-delete-type-mismatch
内存使用率
AddressSanitizer 运行时在执行期间不会将内存释放回 OS,因此不会提前分配内存。 从 OS 的角度来看,看似存在内存泄漏。
AddressSanitizer 运行时 DLL 位置
clang_rt.asan*.dll 运行时文件安装在 %VSINSTALLDIR%\VC\Tools\MSVC\<version>\bin\<host-arch>\<target-arch>\ 中编译器旁边。 这些位置位于调试会话和 Visual Studio 开发人员命令提示符的路径上。 这些文件绝不会放在 C:\Windows\System32 或 C:\Windows\SysWOW64 中。
自定义属性表支持
Visual Studio 属性管理器窗口允许向项目添加自定义 .props 文件。 即使显示 Enable AddressSanitizer 属性(<EnableASAN>),生成也不会遵循它。 生成不遵循它,因为 .props 自定义文件包含在之后 Microsoft.cpp.props,它使用 <EnableASAN> 值来设置其他属性。
解决方法是,在项目的根目录中创建一个 Directory.Build.props 文件来定义 <EnableASAN> 属性。 有关详细信息,请参阅自定义 C++ 生成。
线程局部变量
线程局部变量(使用 __declspec(thread) 或声明的 thread_local全局变量)不受 AddressSanitizer 的保护。 此限制不特定于 Windows 或 Microsoft Visual C++,而是一般限制。
自定义代码跳过普通函数返回序列
不支持使用自定义代码或程序集语言离开当前堆栈帧而不遵循通常的返回机制。 例如,通过长跳离开当前堆栈帧可能会生成误报。
相反,在调用自定义长跳式代码之前,调用 __asan_handle_no_return() 。 此函数清除与当前线程堆栈关联的所有影子字节,这会导致一些覆盖丢失,并引入了误报的风险。 但是,程序随后可以安全地展开堆栈,而不会因堆栈影子字节过期而误报。
部分清理的可执行文件的问题
如果进程中的所有代码未使用 /fsanitize=address编译,ASan 可能无法诊断所有内存安全错误。 最常见的示例是,使用 ASan 编译的 DLL 加载到包含未使用 ASan 编译的代码的进程。 在这种情况下,ASan 尝试对 ASan 初始化之前发生的分配进行分类。 重新分配这些分配后,ASan 会尝试拥有并监视内存的生存期。
如果在进程结束之前从进程卸载了使用 ASan 编译的所有 DLL,则由于对截获的函数(例如memcmp,memcpymemmove等)的悬而未决的引用可能会导致崩溃。 为了获得最佳结果,请使用 编译测试 /fsanitize=address的所有模块,或者不要卸载使用 ASan 编译的模块,然后进入该过程。
请向 开发人员社区报告任何 bug。
ASan 64 位第一次机会异常
在 x64 上,MSVC ASan 的 影子字节 区域占用数 TB 的虚拟地址空间。 ASan 不会预先提交此内存。 而是使用按需分页。 首次访问卷影页时,会发生第一次机会页错误异常,并由提交页面的 ASan 处理。
Visual Studio 调试器可正常处理此情况,并且不显示这些跟踪。 但是,默认情况下,WinDbgX 等调试器可能会中断每个异常。 建议禁用第一次机会异常中断。 例如,在 WinDbgX 中,这对应于 sxd av 命令。
对 C++/CLI 的 ASan 支持是实验性的
对于可靠的 AddressSanitizer (ASan) 诊断,请在本机转换单元或未编译的 DLL 中隔离内存不安全代码,而无需 /clr 使用 /fsanitize=address。 从 C++/CLI 包装器调用本机代码。
CLR 管理内存和 JIT 生成的代码,因此无法保证 C++/CLI 代码接收 ASan 加载和存储检测。 因此:
- C++/CLI 和 STL 代码:可能无法检测 C++/CLI 方法中的内存访问,包括 STL 代码执行的访问。
- 托管数组:范围外访问生成 CLR 行为,例如
IndexOutOfRangeException,而不是 ERROR:AddressSanitizer 报告。 - 托管线程:C++/CLI 方法正文中发出的本机内存访问可能不会生成 ASan 诊断。
- 最终化和关闭:在最终化、进程关闭或混合模式卸载期间的报告可能无法可靠地指示用户代码内存 bug。
- 本机主机:从本机主机加载启用了 ASan 的 C++/CLI 包装器 DLL 可能会产生误导性的运行时故障,例如未知地址的访问冲突报告。
另请参阅
AddressSanitizer 概述
AddressSanitizer 生成和语言参考
AddressSanitizer 运行时参考
AddressSanitizer 阴影字节
AddressSanitizer 云或分布式测试
AddressSanitizer 调试程序集成
AddressSanitizer 错误示例