如何让Sanitizer检测预定义存储中placement new的内存泄漏?
如何让Sanitizer检测预定义存储中内存分配导致的内存泄漏?
在使用Sanitizer做内存泄漏检测时,你会发现bar()里的普通堆分配会被正常检测到泄漏,但foo()中用**定位new(placement new)**在全局预定义存储上构造对象的操作,Sanitizer完全不会报警。这是因为Sanitizer默认只追踪堆内存的分配,而全局/静态预定义存储不属于堆范畴,不会被自动监控。
解决方法:手动标记内存区域的生命周期
要让Sanitizer追踪这类内存,需要使用它提供的非标准内置函数,手动标记内存的分配与释放状态,让Sanitizer把这块区域纳入监控范围。
修改后的示例代码如下:
#include <iostream> #include <type_traits> class A { }; typename std::aligned_storage<256, alignof(256)>::type store; A* foo() { // 告知Sanitizer这块内存已被分配 __sanitizer_allocated_memory(&store, sizeof(store)); return new (&store) A(); } // 手动销毁对象并标记内存释放 void cleanup_foo(A* ptr) { ptr->~A(); // 显式调用析构函数 __sanitizer_deallocated_memory(&store, sizeof(store)); } A* bar() { return new A(); } int main() { A* a = foo(); cleanup_foo(a); // 先清理旧对象再重新构造 a = foo(); A* a2 = bar(); a2 = bar(); }
关键说明
- 定位new本身不分配内存,只是在已有内存上构造对象,所以Sanitizer默认不会追踪。通过
__sanitizer_allocated_memory和__sanitizer_deallocated_memory,我们手动将这块预定义存储模拟成堆内存的生命周期,让Sanitizer可以监控其上的对象状态。 - 如果重复调用
foo()却不销毁前一个对象,Sanitizer就能检测到前一个对象的资源泄漏(如果A类内部有堆分配的成员变量)。 - 这些内置函数是Sanitizer的扩展,仅在使用
-fsanitize=address编译时有效,不属于C++标准。
内容的提问来源于stack exchange,提问作者getsoubl
相关产品推荐
相关产品推荐

