It is very serious. With new[]
, implementations typically store somewhere the number of allocated array elements, since they need to know how many of them will be destructed by delete[]
.
Compare allocation and deallocations of a single object with new
/delete
and new[]
/delete
: https://godbolt.org/z/GYTh7f7Y7. You can clearly see that the machine code in the latter case is much more complicated. Note that new[]
stores the number of elements (1) to the beginning of the allocated memory with mov QWORD PTR [rax], 1
. delete[]
then reads this number with mov rsi, QWORD PTR [rdi-8]
to be able to iterate over elements and call their destructors.
Ordinary new
does not store this number, so consequently, when you use new
together with delete[]
, delete[]
will read some unspecified number and apply destructors to unpredicted memory. This can create serious vulnerability problems.
The opposite new[]
plus delete
case is also very wrong. Ordinary new
expression typically returns a pointer that points exactly to the memory block internally allocated by operator new
(which usually calls malloc
). This pointer when passed to delete
expression is then internally passed as-is to the operator delete
deallocation function.
But the same does not hold for new[]
. Namely, new[]
does not return a pointer obtained internally by operator new
. Instead, it returns this pointer increased by 8 bytes (with GCC, but I think the same holds for Clang and MSVC on x86_64). See that lea r12, [rax+8]
in the linked assembly. In these 8 bytes, the number of allocated array elements is stored. Consequently, if you apply delete
to what you obtained with new[]
, delete
will pass to operator delete
a pointer that has not been allocated with operator new
, because it will not subtract those 8 bytes from it. This will finally likely cause some like heap corruption.