使用 AddressSanitizer 检测堆越界错误
在 C/C++ 编程中,堆越界(Heap Buffer Overflow) 是一种常见且危险的内存错误。当程序访问了动态分配(如 malloc
或 new
)的内存之外的区域时,就会发生这种错误。幸运的是,借助 AddressSanitizer(ASan),我们可以轻松地检测并定位这类问题。
示例代码:堆越界错误
下面是一个简单的堆越界示例程序:
#include <iostream>
#include <cstdlib>
#include <cstring>int main() {char* buffer = (char*)malloc(10);std::strcpy(buffer, "HelloWorld!"); // 11 bytes including '\0'std::cout << buffer << std::endl;free(buffer);return 0;
}
问题分析
-
使用
malloc(10)
分配了 10 字节的堆内存; -
然后使用
strcpy
复制了"HelloWorld!"
,它包含 11 字节(含结尾的\0
); -
结果写入了超出分配范围的地址,导致堆缓冲区溢出。
编译并使用 ASan 检测
使用 Clang 或 GCC 时加上 -fsanitize=address -g
选项,即可启用 ASan:
g++ -fsanitize=address -g heap_overflow.cpp -o heap_overflow
编译完成后执行:
./heap_overflow
复制编辑
AddressSanitizer 报告解读
运行后,ASan 会输出类似下面的错误报告:
报告说明:
-
heap-buffer-overflow on address 0x60200000001a at pc 0x7f2729b872c3 bp 0x7ffe2a8905a0 sp 0x7ffe2a88fd48
: 表明访问了超出堆缓冲区末尾的地址; -
WRITE of size 12 at 0x60200000001a thread T0
: 表示发生了写操作; -
0x60200000001a is located 0 bytes to the right of 10-byte region [0x602000000010,0x60200000001a)
: 明确指出访问的地址越界和越界的大小; -
allocated by thread T0 here
: 显示了堆内存的分配位置; -
heap_overflow.cpp:7
: 指出越界代码的位置在第 7 行,即strcpy
语句。
修复建议
正确的做法是分配足够的空间,包括字符串末尾的 \0
字符:
char* buffer = (char*)malloc(11); // 或使用 strlen + 1 动态计算
std::strcpy(buffer, "HelloWorld!");
总结
-
堆越界 是 C/C++ 中隐蔽而危险的错误类型;
-
ASan 可以快速检测并定位这类问题,极大提升程序的安全性;
-
编写 C/C++ 代码时应特别注意内存边界,防止访问越界。