如何检测C++中Placement New创建对象的越界访问(内存块内)
示例代码
#include <iostream> struct mix { int64_t x[10]; }; int main() { int64_t* p = new int64_t[100]; mix* px = new (p) mix; mix* py = new (p + 10) mix; px->x[12] = 104; std::cout << py->x[2] << std::endl; delete[] p; }
问题背景
这段代码里,px和py是在同一块分配的内存中通过placement new构造的对象。访问px->x[12]时,虽然没超出总内存块p的范围,但已经越界了mix对象自身的边界。
常规的-fsanitize=address、默认配置的-fsanitize=undefined和Valgrind都不会报告这种越界,因为它们只检查是否超出了分配的内存块整体边界,而非单个对象的边界。现在需要一种无需修改源代码、允许性能损失的方案,来严格检测这类跨对象的越界访问。
可行方案
1. Clang 启用object-size UBSan检测
Clang的UndefinedBehaviorSanitizer(UBSan)提供了object-size检测选项,它会跟踪每个对象的实际大小,检查访问是否超出对象自身的边界,哪怕内存仍在全局分配块内。编译时添加参数:
clang++ -fsanitize=undefined,object-size -o test test.cpp
运行程序后,会直接触发报错,明确指出px->x[12]越界访问了mix对象的成员数组。
2. GCC 启用bounds-strict UBSan检测
GCC 10及以上版本支持bounds-strict选项,属于UBSan的扩展,它会严格校验数组下标是否在对象自身的边界内,而非仅看分配的内存块。编译命令:
g++ -fsanitize=undefined,bounds-strict -o test test.cpp
运行后同样会捕获到px->x[12]的越界行为。
3. Intel Inspector 动态检测
Intel Inspector是一款专业的内存错误检测工具,能够识别通过placement new创建的对象边界,检测对象内部的越界访问。只需将编译后的程序导入Inspector,运行内存错误检测任务,就能定位到该问题。
4. Clang Static Analyzer 静态分析
Clang静态分析器可以在编译阶段就识别出这类对象越界访问。执行以下命令进行分析:
clang++ --analyze -Xanalyzer -analyzer-checker=core test.cpp
分析后会输出针对px->x[12]的越界警告,无需运行程序就能提前发现问题。
内容的提问来源于stack exchange,提问作者种传龙

