ASAN new_delete_type_mismatch

I’ve been working on improving the aligned and sized allocation/deallocation checks in Valgrind, with a release due out in a few weeks.

I have some doubts as to what should be done in the case where an aligned new gets freed by a delete without alignment. 7.6.2.8 in C++20 says

[Note: If this results in a call to
a replaceable deallocation function, and either the first argument was not the result of a prior call to a
replaceable allocation function or the second or third argument was not the corresponding argument in said call, the behavior is undefined (17.6.2.1, 17.6.2.2). — end note]

That’s saying that if operator delete has a sized or aligned argument it must match the operator new for the pointer being deleted.

7.6.2.8 para 10.2 says that aligned delete is preferred for types with alignment.

I don’t see anything that requires pointers allocated with aligned new to be freed with aligned delete. If I understand correctly, C23 has similar rules for sized and aligned free, i.e., if you do use free_aligned_sized() the arguments need to match aligned_alloc() but you can still use plain free().

Here’s an example.

#include <new>

int main()
{
   void *mem = operator new(1024U, static_cast<std::align_val_t>(256U));
   operator delete(mem);
}

I don’t get any error with GCC ASAN or with Valgrind, but LLVM ASAN gives me

=================================================================
==47660==ERROR: AddressSanitizer: new-delete-type-mismatch on 0x61a000000100 in thread T0:
  object passed to delete has wrong type:
  alignment of the allocated type:   256 bytes;
  alignment of the deallocated type: default-aligned.
    #0 0x2d50dd in operator delete(void*) /usr/src/contrib/llvm-project/compiler-rt/lib/asan/asan_new_delete.cpp:152:3
    #1 0x2d6e03 in main /home/paulf/scratch/align/align.cpp:6:4
    #2 0x23abcf in _start /usr/src/lib/csu/amd64/crt1_c.c:75:7
    #3 0x8002fc007  (<unknown module>)

0x61a000000100 is located 0 bytes inside of 1024-byte region [0x61a000000100,0x61a000000500)
allocated by thread T0 here:
    #0 0x2d4ca2 in operator new(unsigned long, std::align_val_t) /usr/src/contrib/llvm-project/compiler-rt/lib/asan/asan_new_delete.cpp:107:3
    #1 0x2d6df6 in main /home/paulf/scratch/align/align.cpp:5:16
    #2 0x23abcf in _start /usr/src/lib/csu/amd64/crt1_c.c:75:7
    #3 0x8002fc007  (<unknown module>)

SUMMARY: AddressSanitizer: new-delete-type-mismatch /usr/src/contrib/llvm-project/compiler-rt/lib/asan/asan_new_delete.cpp:152:3 in operator delete(void*)
==47660==HINT: if you don't care about these errors you may set ASAN_OPTIONS=new_delete_type_mismatch=0
==47660==ABORTING

Is LLVM being a little overzealous? I agree that aligned delete should be used, but I don’t think that the standard requires it.

Paul

I think you’re missing [new.delete.single]/11 which specifies some of the preconditions of the standard-library-provided implementations of operator delete:

If the alignment parameter is not present, ptr was returned by an allocation function without an alignment parameter. If present, the alignment argument is equal to the alignment argument passed to the allocation function that returned ptr. If present, the size argument is equal to the size argument passed to the allocation function that returned ptr.

These preconditions don’t apply to replaced operator deletes: a user is welcome to add or remove any preconditions they like for their implementation of operator delete. Perhaps this is the reason for the divergence between the Clang and GCC implementations of ASan?

I think that you are right.

GCC 13.1 on RHEL 7.9 also generates an error for this.

Let’s see if I can fix it in Valgrind in time for the release.