ASan报new_delete_type_mismatch:对齐new需配对对齐delete吗?
对齐new/delete配对问题与ASan报错解析
问题重现
以下代码用g++ 14.2.1加-Wall -pedantic编译无警告,运行正常,但启用-fsanitize=address后,ASan抛出类型不匹配错误:
#include <new> int main() { delete new (std::align_val_t(16)) char; }
ASan报错内容:
==17707==ERROR: AddressSanitizer: new-delete-type-mismatch on 0x503000000040 in thread T0: object passed to delete has wrong type: size of the allocated type: 1 bytes; size of the deallocated type: 1 bytes. alignment of the allocated type: 16 bytes; alignment of the deallocated type: default-aligned. #0 0x70912beff4f2 in operator delete(void*, unsigned long) /usr/src/debug/gcc/gcc/libsanitizer/asan/asan_new_delete.cpp:164 #1 0x6493bc2dd18d in main (/tmp/a.out+0x118d) (BuildId: e8f06d0aee8e301d7f1522801237096f3006c790) #2 0x70912b835487 (/usr/lib/libc.so.6+0x27487) (BuildId: 695cfc6aac7d0f77bb7caba0ef01b2e868762b02) #3 0x70912b83554b in __libc_start_main (/usr/lib/libc.so.6+0x2754b) (BuildId: 695cfc6aac7d0f77bb7caba0ef01b2e868762b02) #4 0x6493bc2dd094 in _start (/tmp/a.out+0x1094) (BuildId: e8f06d0aee8e301d7f1522801237096f3006c790) 0x503000000040 is located 0 bytes inside of 1-byte region [0x503000000040,0x503000000041) allocated by thread T0 here: #0 0x70912befe97a in operator new(unsigned long, std::align_val_t) /usr/src/debug/gcc/gcc/libsanitizer/asan/asan_new_delete.cpp:107 #1 0x6493bc2dd17b in main (/tmp/a.out+0x117b) (BuildId: e8f06d0aee8e301d7f1522801237096f3006c790) #2 0x70912b835487 (/usr/lib/libc.so.6+0x27487) (BuildId: 695cfc6aac7d0f77bb7caba0ef01b2e868762b02) #3 0x70912b83554b in __libc_start_main (/usr/lib/libc.so.6+0x2754b) (BuildId: 695cfc6aac7d0f77bb7caba0ef01b2e868762b02) #4 0x6493bc2dd094 in _start (/tmp/a.out+0x1094) (BuildId: e8f06d0aee8e301d7f1522801237096f3006c790) SUMMARY: AddressSanitizer: new-delete-type-mismatch /usr/src/debug/gcc/gcc/libsanitizer/asan/asan_new_delete.cpp:164 in operator delete(void*, unsigned long)
核心问题解答
这是不是ASan的误报?
不是误报。ASan准确检测到了分配和释放时的对齐属性不匹配——用16字节对齐的new分配内存,却用默认对齐的delete释放,这属于标准定义的问题场景。必须将对齐new和对齐delete配对吗?
是的,必须配对。根据C++标准[new.delete]章节的规定:用带std::align_val_t参数的operator new分配的内存,必须用带对应std::align_val_t参数的operator delete来释放。不配对会导致未定义行为吗?
会。标准明确指出,这种不匹配的释放操作属于未定义行为。虽然某些编译器/平台下可能“看起来正常”,但这完全依赖实现细节,移植性和稳定性无法保证,极端情况下可能导致内存泄露、堆损坏或程序崩溃。
过度对齐内存释放的最佳实践
对于SIMD场景中32字节对齐的double数组这类过度对齐内存,最佳实践如下:
- 显式调用带对齐参数的operator delete:分配时用
new (std::align_val_t(32)) double[N],释放时必须对应调用operator delete[](ptr, std::align_val_t(32)),数组版的对齐new要对应数组版的对齐delete。 - 避免裸指针管理:优先使用智能指针,并自定义删除器来确保对齐释放。示例:
#include <memory> #include <new> int main() { constexpr std::size_t align = 32; auto deleter = [](double* p) { operator delete[](p, std::align_val_t(align)); }; std::unique_ptr<double, decltype(deleter)> ptr( new (std::align_val_t(align)) double[8], deleter ); } - 用std::aligned_alloc替代(C风格分配):如果用C风格的
std::aligned_alloc分配,必须用std::free释放,但要注意std::aligned_alloc的大小必须是对齐值的整数倍,这点和C++的对齐new不同。
内容的提问来源于stack exchange,提问作者YiFei
相关产品推荐
相关产品推荐

