new c++ new/delete overloads need wrapping?
Jeremy Drake
cygwin@jdrake.com
Fri Jul 25 17:28:54 GMT 2025
On 2025年7月25日, Corinna Vinschen via Cygwin wrote:
> On Jul 24 22:41, Jeremy Drake via Cygwin wrote:
> > I was looking into C++ new/delete --wrap linker options, and noticed that
> > in a quick test the wrapper for delete was not being called. This was
> > because delete is being compiled to _ZdlPvm and that symbol is not present
> > in the --wrap arguments in the GCC spec, and is not part of the
> > per_process_cxx_malloc struct. I'm not seeing anything in that cxx_malloc
> > struct like a size or version number, so I don't know a good way to
> > extend it given that it is part of the startup code linked into every
> > binary.
> >
> > Here are the current symbols from libc++ and how they demangle:
> >
> > _ZdaPv operator delete[](void*)
> > _ZdaPvm operator delete[](void*, unsigned long)
> > _ZdaPvmSt11align_val_t operator delete[](void*, unsigned long, std::align_val_t)
> > _ZdaPvRKSt9nothrow_t operator delete[](void*, std::nothrow_t const&)
> > _ZdaPvSt11align_val_t operator delete[](void*, std::align_val_t)
> > _ZdaPvSt11align_val_tRKSt9nothrow_t operator delete[](void*, std::align_val_t, std::nothrow_t const&)
> > _ZdlPv operator delete(void*)
> > _ZdlPvm operator delete(void*, unsigned long)
> > _ZdlPvmSt11align_val_t operator delete(void*, unsigned long, std::align_val_t)
> > _ZdlPvRKSt9nothrow_t operator delete(void*, std::nothrow_t const&)
> > _ZdlPvSt11align_val_t operator delete(void*, std::align_val_t)
> > _ZdlPvSt11align_val_tRKSt9nothrow_t operator delete(void*, std::align_val_t, std::nothrow_t const&)
> > _Znam operator new[](unsigned long)
> > _ZnamRKSt9nothrow_t operator new[](unsigned long, std::nothrow_t const&)
> > _ZnamSt11align_val_t operator new[](unsigned long, std::align_val_t)
> > _ZnamSt11align_val_tRKSt9nothrow_t operator new[](unsigned long, std::align_val_t, std::nothrow_t const&)
> > _Znwm operator new(unsigned long)
> > _ZnwmRKSt9nothrow_t operator new(unsigned long, std::nothrow_t const&)
> > _ZnwmSt11align_val_t operator new(unsigned long, std::align_val_t)
> > _ZnwmSt11align_val_tRKSt9nothrow_t operator new(unsigned long, std::align_val_t, std::nothrow_t const&)
>> Wow, these got a lot more since we started to support this back in
> 2009 and ported to 64 bit in 2013.
Yeah, it looks like they added aligned new/delete and sized delete, and
then had a combinatorial explosion.
> But first I have to tell you that I'm fuzzy on how this exactly is
> working together. I can't tell you how this affects GCC or LD.
I was looking at this because it's not working correctly with LLD.
> Nevertheless, the code overriding the members in per_process_cxx_malloc
> is living in the app (_cygwin_crt0_common.cc). If you just append members
> to per_process_cxx_malloc nad implement the wrappers in cxx.cc and
> libstdcxx_wrapper.cc, then old apps using the old _cygwin_crt0_common.cc
> will just not see the new functions. So that should work out of the
> box, shouldn't it?
I missed a pointer dereference in _cygwin_crt0_common.cc that meant the
struct was being copied rather than the pointer replaced. I was concerned
that a pointer to the old struct might be used, and garbage found in the
new fields. I see now that it copies the contents, and if the struct is
smaller it will obviously leave the new fields alone.
I came across this comment that concerned me though
/* Broken DLLs built against Cygwin versions 1.7.0-49 up to 1.7.0-57
override the cxx_malloc pointer in their DLL initialization code,
when loaded either statically or dynamically. Because this leaves
a stale pointer into demapped memory space if the DLL is unloaded
by a call to dlclose, we prevent this happening for dynamically
loaded DLLs in dlopen by saving and restoring cxx_malloc around
the call to LoadLibrary, which invokes the DLL's startup sequence.
Modern DLLs won't even attempt to override the pointer when loaded
statically, but will write their overrides directly into the
struct it points to. With all modern DLLs, this will remain the
default_cygwin_cxx_malloc struct in cxx.cc, but if any broken DLLs
are in the mix they will have overridden the pointer and subsequent
overrides will go into their embedded cxx_malloc structs. This is
almost certainly not a problem as they can never be unloaded, but
if we ever did want to do anything about it, we could check here to
see if the pointer had been altered in the early parts of the DLL's
startup, and if so copy back the new overrides and reset it here.
However, that's just a note for the record; at the moment, we can't
see any need to worry about this happening. */
I don't see the save and restore mentioned in dlopen... Are these old
DLLs sufficiently old that there wasn't 64-bit yet, and therefore can't be
used anymore?
More information about the Cygwin
mailing list