使用 Visual C++ 的地址清理程序:忽略读取缓冲区溢出,同时仍捕获写入缓冲区溢出
Posted
技术标签:
【中文标题】使用 Visual C++ 的地址清理程序:忽略读取缓冲区溢出,同时仍捕获写入缓冲区溢出【英文标题】:Address Sanitizer with Visual C++: ignore read buffer overflows while still catching write buffer overflows 【发布时间】:2021-12-11 14:25:00 【问题描述】:考虑以下示例:
int main()
char* p = new char[10];
srand(p[11]); // heap buffer overflow - read
p[11] = rand(); // heap buffer overflow - write
我希望 ASan 暂时不要标记 heap buffer overflow - read
,同时仍标记 heap buffer overflow - write
。
我想要这样做的原因是现在专注于更危险的错误。读取溢出要么立即崩溃,要么没有后果,而写入溢出可能会导致稍后在其他地方触发的损坏。对于一些小的溢出,即使是立即崩溃也被排除在外。所以我肯定也会研究读取溢出,但稍后。
有没有办法做到这一点?
【问题讨论】:
【参考方案1】:实现这一点有两个方向。
1。触发错误后继续
要在出错后继续,应使用-fsanitize-recover=address
选项。来自FAQ:
问:AddressSanitizer 在报告第一个错误后能否继续运行?
A:可以,AddressSanitizer 最近获得了错误后继续模式。这有点实验性,因此可能还不如默认设置可靠(并且不及时支持)。还要记住,第一个错误之后的错误实际上可能是虚假的。要启用错误后继续,请使用
-fsanitize-recover=address
编译,然后使用ASAN_OPTIONS=halt_on_error=0
运行您的代码。
MSVC 编译器尚不支持此选项。有一个issue 可以添加它。
如果可行,则可以安装一个自定义处理程序来检查它是读取还是写入错误,忽略读取错误并报告写入错误。
2。不要检测读取错误
正如@yugr 所指出的,有-mllvm -asan-instrument-reads=false
选项可以实现这一点。但是 MSVC 编译器也不支持这个选项。
但仍有一些方法可以避免在某些地方使用编译器检测。它是__declspec(no_sanitize_address)
。因此,可以通过隔离已知的读取错误来实现目标,如下所示:
__declspec(no_sanitize_address)
void isolate_read_heap_buffer_overflow(char* p)
srand(p[11]); // heap buffer overflow - read
int main()
char* p = new char[10];
isolate_read_heap_buffer_overflow(p);
p[11] = rand(); // heap buffer overflow - write
return 0;
其他更好的选择
还有clang-cl
编译器,其实就是支持Visual C++语义的Clang。 Visual Studio 安装程序会安装它。因此,如果可以重新定位项目以使用 Clang,这将打开 Clang 中可用的所有 Address Sanitizer 功能。不幸的是,重新定位一些遗留代码库可能是一项漫长的任务。
【讨论】:
【参考方案2】:理论上,向 CL 包装器提供 -mllvm -asan-instrument-reads=false
应该会禁用读取检测。
【讨论】:
我已经编辑了我的答案来提及这一点,我也找到了一个可以接受的解决方案以上是关于使用 Visual C++ 的地址清理程序:忽略读取缓冲区溢出,同时仍捕获写入缓冲区溢出的主要内容,如果未能解决你的问题,请参考以下文章
C++ 指针使用 Visual Studio 更改地址,而不是使用 OsX 中的 Xcode 或 Linux 中的 gcc
用啥软件来查看一个用Microsoft Visual C++ 6.0 编写的程序的源代码
Visual Studio 2008 C++ 误报内存地址位置
应用程序重新启动 C++ Visual Studio 时保存编辑控件用户输入和恢复的有效方法