Bug 511932

Summary: bogus "Mismatched new/delete size" for delete of pointer to base class
Product: [Developer tools] valgrind Reporter: Olly Betts <ojwbetts+kde>
Component: memcheckAssignee: Julian Seward <jseward>
Status: RESOLVED NOT A BUG    
Severity: normal CC: pjfloyd, tom
Priority: NOR    
Version First Reported In: 3.25.1   
Target Milestone: ---   
Platform: Debian unstable   
OS: Linux   
Latest Commit: Version Fixed/Implemented In:
Sentry Crash Report:

Description Olly Betts 2025-11-10 21:07:00 UTC
SUMMARY

Deleting a C++ object via a pointer to its base class is a valid operation - https://en.cppreference.com/w/cpp/language/delete.html says:

    ptr must be one of [...] a pointer to a base subobject of a non-array object created by a new-expression.

However recent versions of valgrind complain about the size being mismatched.

STEPS TO REPRODUCE

$ cat del.cc
struct B {
    int x;
};

struct C : public B {
    int y;
};

int main() {
    B* x = new C();
    delete x;
}
$ g++ del.cc
$ valgrind --tool=memcheck ./a.out
==1002990== Memcheck, a memory error detector
==1002990== Copyright (C) 2002-2024, and GNU GPL'd, by Julian Seward et al.
==1002990== Using Valgrind-3.25.1 and LibVEX; rerun with -h for copyright info
==1002990== Command: ./a.out
==1002990== 
==1002990== Mismatched new/delete size value: 4
==1002990==    at 0x484D809: operator delete(void*, unsigned long) (vg_replace_malloc.c:1181)
==1002990==    by 0x4001197: main (in /home/olly/a.out)
==1002990==  Address 0x4e43080 is 0 bytes inside a block of size 8 alloc'd
==1002990==    at 0x4849F93: operator new(unsigned long) (vg_replace_malloc.c:487)
==1002990==    by 0x400115A: main (in /home/olly/a.out)
==1002990== 
==1002990== 
==1002990== HEAP SUMMARY:
==1002990==     in use at exit: 0 bytes in 0 blocks
==1002990==   total heap usage: 2 allocs, 2 frees, 73,736 bytes allocated
==1002990== 
==1002990== All heap blocks were freed -- no leaks are possible
==1002990== 
==1002990== For lists of detected and suppressed errors, rerun with: -s
==1002990== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

OBSERVED RESULT

==1002990== Mismatched new/delete size value: 4

EXPECTED RESULT

No valgrind errors.

SOFTWARE/OS VERSIONS

This is using the Debian unstable using valgrind package 3.25.1-3.

ADDITIONAL INFORMATION

I can also reproduce with 3.24.0-3 but not 3.20.0-2.1 (that's as tightly as I can narrow it down using package versions in the Debian snapshot service).

Looking at the changelog, it seems these checks were added in 3.22.0, but that was over 2 years ago and even 3.24.0 was over a year ago so I'm not sure why I've only just started to notice this as my non-reduced code that triggers this is much older than that and regularly testing with valgrind.  Maybe GCC or libstdc++ has changed to calling the sized delete?
Comment 1 Paul Floyd 2025-11-11 07:46:26 UTC
The first problem with this bug report is that you are using pejorative language to describe the issue. Just stick to the facts.

The real problem is that your code is wrong.

You did not read this part of the cppreference description:

"If ptr is a pointer to a base class subobject of the object that was allocated with new, the destructor of the base class must be virtual, otherwise the behavior is undefined. "

Is your destructor virtual? No. So your code has UB and Valgrind is correctly diagnosing a genuine error.

If I add a destuctor the B and rerun your code I get no errors.
Comment 2 Tom Hughes 2025-11-11 08:37:43 UTC
Specifically what is happening is that because the destructor is not virtual you are calling the base class destructor, which tries to free a base class object, which is only 4 bytes in size.

If the destructor was virtual it would have called the derived class destructor, which would free a derived class object, which would be 8 bytes in size. Well actually it would probably be 16 bytes then because adding the virtual destructor would have added a vtable pointer...
Comment 3 Olly Betts 2025-11-11 19:40:52 UTC
Aha, thanks - I had indeed missed that later note about needing a virtual destructor.  Sorry about the noise.

(I'm still puzzled why this seems to have only started to trigger recently though...)
Comment 4 Paul Floyd 2025-11-12 06:43:55 UTC
This is a relatively new feature, it was added in March 2023 (see below) and released with Valgrind 3.22 in October of the same year.

This bug report mentions Debian unstable. If I understand this changelog correctly https://metadata.ftp-master.debian.org/changelogs//main/v/valgrind/valgrind_3.25.1-3_changelog then the Debian port switched from 3.20 (Oct 2022) to 3.24 (Oct 2024) in January this year.

Author: Paul Floyd <pjfloyd@wanadoo.fr>  2023-03-12 08:26:04
Committer: Paul Floyd <pjfloyd@wanadoo.fr>  2023-09-02 16:12:35
Parent: 6489bc63a13fcf614cdb1cb318ea9a1f898a39cd (regtest: make memcheck sem test quiet)
Child:  86a8f04c7f5d31050d841e82397f052fc6a958a6 (regtest: silence a few warnings)
Branches: master, remotes/origin/master and many more (23)
Follows: VALGRIND_3_21_0
Precedes: VALGRIND_3_22_0

    Add memcheck errors for aligned and sized allocations and deallocations
    
    Bug 433857 Add validation to C++17 aligned new/delete alignment size
    Bug 433859 Add mismatched detection to C++ 17 aligned new/delete
    Bug 466105 aligned_alloc problems, part 2
    Bug 467441 Add mismatched detection to C++ 14 sized delete