Consider the following code snippet:
#include <new>
int main() {
delete new (std::align_val_t(16)) char;
}
g++ 14.2.1 compiles it without warning (under -Wall -pedantic
) and it runs without error. But when compiled with -fsanitize=address
, ASan reports the following:
==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)
Is this a false positive by ASan? Or is it actually required to pair "aligned new" calls with "aligned delete" calls? Is it undefined behavior if not paired?
Edit: I suppose [new.delete] is relevant. But then my question becomes what is the best practice for freeing over-aligned memory (say, 32-byte aligned array of doubles for SIMD purposes)? Is it best to call operator delete
explicitly?
Consider the following code snippet:
#include <new>
int main() {
delete new (std::align_val_t(16)) char;
}
g++ 14.2.1 compiles it without warning (under -Wall -pedantic
) and it runs without error. But when compiled with -fsanitize=address
, ASan reports the following:
==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)
Is this a false positive by ASan? Or is it actually required to pair "aligned new" calls with "aligned delete" calls? Is it undefined behavior if not paired?
Edit: I suppose [new.delete] is relevant. But then my question becomes what is the best practice for freeing over-aligned memory (say, 32-byte aligned array of doubles for SIMD purposes)? Is it best to call operator delete
explicitly?
1 Answer
Reset to default 0ASAN is right and reports the issue correctly. std::align_val_t:
Both new-expression and delete-expression, when used with objects whose alignment requirement is greater than
__STDCPP_DEFAULT_NEW_ALIGNMENT__
, pass that alignment requirement as an argument of typestd::align_val_t
to the selected allocation/deallocation function.
The correct usage:
::operator delete (new (std::align_val_t(16)) char, std::align_val_t(16));
https://godbolt.org/z/zrK1ffdEx