ASAN未检测到缓冲区溢出:为何此C++代码的越界操作未被识别?
AddressSanitizer未检测到缓冲区溢出的原因与修复方案
问题代码
#include <iostream> #include <type_traits> thread_local std::aligned_storage_t<1024> data; int main() { std::cout << sizeof(data) << std::endl; uint8_t * d = new (&data) uint8_t[1024]; d[1025] = '6'; std::cout << d[1025] << std::endl; }
这段代码通过placement new在thread_local的std::aligned_storage_t<1024>内存上构造了uint8_t数组,随后对数组执行下标为1025的越界赋值与访问,但AddressSanitizer(ASAN)并未触发缓冲区溢出告警。
核心原因
ASAN的缓冲区溢出检测依赖于**在内存块前后添加受保护的红区(redzone)**并跟踪内存分配元数据,但当前场景不满足检测条件:
std::aligned_storage_t<1024>是线程本地静态分配的内存,不属于ASAN跟踪的堆内存范畴,ASAN不会为这类静态内存自动添加红区。- placement new仅在已有内存区域上构造对象,不会向ASAN注册新的内存分配信息——ASAN无法识别这块内存被用作长度为1024的数组,只会按原始
aligned_storage_t<1024>的大小处理,越界到1025的操作未触及ASAN保护区域,因此不会触发告警。
修复方案
方案1:改用堆分配(最简单)
将placement new替换为普通堆分配,ASAN会自动为堆内存添加红区并跟踪边界:
#include <iostream> int main() { uint8_t * d = new uint8_t[1024]; std::cout << sizeof(*d) * 1024 << std::endl; d[1025] = '6'; // ASAN会立即检测到越界并报错 std::cout << d[1025] << std::endl; delete[] d; }
方案2:手动标记内存边界(保留thread_local场景)
如果必须使用线程本地内存,可通过ASAN接口手动标记内存有效范围,将数组末尾之外的区域标记为有毒(poisoned):
#include <iostream> #include <type_traits> #include <sanitizer/asan_interface.h> thread_local std::aligned_storage_t<1024> data; int main() { std::cout << sizeof(data) << std::endl; uint8_t * d = new (&data) uint8_t[1024]; // 标记数组末尾后的内存为有毒,触发越界检测 __asan_poison_memory_region(d + 1024, sizeof(data) - 1024); d[1025] = '6'; // ASAN会检测到该越界操作 std::cout << d[1025] << std::endl; }
注意:使用ASAN接口需要确保编译时链接了ASAN库,且包含头文件
<sanitizer/asan_interface.h>。
内容的提问来源于stack exchange,提问作者getsoubl
相关产品推荐
相关产品推荐

