使用Container注解包装器让ASan检测栈内存缓冲区溢出失效问题
为何ASan未检测到栈内存的缓冲区溢出?
你的测试代码如下:
#include <sanitizer/asan_interface.h> #include <iostream> #include <array> constexpr size_t N = 32; class A { public: int x; }; int main() { char buf [sizeof(A)]; A *a = new (buf) A; __sanitizer_annotate_contiguous_container(buf, buf + sizeof(A), buf, buf + sizeof(A)); a->~A(); a[sizeof(A) + 64].x = 4; std::cout << a[sizeof(A) + 64].x << std::endl; }
ASan未触发检测的原因主要有三点:
__sanitizer_annotate_contiguous_container不适用于栈内存
这个注解函数是专门为**堆上的动态容器(比如std::vector)**设计的,用于标记容器的有效元素范围,辅助ASan检测容器内部的越界访问。但栈上的数组由ASan在编译阶段通过栈帧红区机制监控,这个注解不会改变栈内存的检测规则,对栈内存完全无效。指针算术的实际偏移超出栈红区监控范围
你使用a[sizeof(A)+64]访问内存时,由于a是A*类型,下标会自动乘以sizeof(A)。假设sizeof(A)=4,实际偏移量是(4+64)*4=272字节——这个地址可能没有落在当前栈帧的红区(ASan为栈帧分配的保护区域),而是落在栈的其他合法区域甚至进程的可访问内存中,ASan自然不会触发错误。对象析构后栈内存未被标记为不可访问
调用a->~A()仅完成对象的析构,但栈上的buf内存依然属于当前栈帧的一部分,ASan不会自动将其标记为不可访问的Poisoned区域。如果要检测对已析构对象内存的非法访问,需要手动调用__asan_poison_memory_region(buf, sizeof(A))。
修复示例
如果要让ASan检测到内存违规,可以修改代码手动标记栈内存为不可访问:
#include <sanitizer/asan_interface.h> #include <iostream> class A { public: int x; }; int main() { char buf [sizeof(A)]; A *a = new (buf) A; // 手动标记buf内存为不可访问 __asan_poison_memory_region(buf, sizeof(A)); // 访问a[1]会触发ASan越界检测 a[1].x = 4; std::cout << a[1].x << std::endl; }
或者用堆内存测试注解的效果:
#include <sanitizer/asan_interface.h> #include <iostream> #include <malloc.h> class A { public: int x; }; int main() { size_t buf_size = sizeof(A) * 2; char *buf = (char*)malloc(buf_size); A *a = new (buf) A; // 标注容器的有效范围为buf到buf+sizeof(A) __sanitizer_annotate_contiguous_container(buf, buf + buf_size, buf, buf + sizeof(A)); a->~A(); // 访问a[1]超出有效范围,触发ASan错误 a[1].x = 4; std::cout << a[1].x << std::endl; free(buf); }
内容的提问来源于stack exchange,提问作者getsoubl
相关产品推荐
相关产品推荐

