Accept NULL in free_sized() and free_aligned_sized()

free_sized() and free_aligned_sized() forward straight to sdallocx(), which
expects a non-NULL pointer and asserts on it in debug builds. C23 says both
should accept NULL and do nothing, like free(NULL) does, so a NULL argument
either trips that assert or feeds NULL into the dealloc path in release builds.

It is not hard to hit. glibc 2.41 ships free_sized()/free_aligned_sized(), and
a C++ sized delete of a null pointer compiles down to a free_sized() call. Once
jemalloc is preloaded its versions take over, and that NULL call takes down the
process. I ran into it with GTK4/GLib apps under LD_PRELOAD.

Check for NULL first, the way free() already does, and add an integration test
covering the NULL case for both functions.

While here, give free_aligned_sized() its own core.free_aligned_sized.entry
and .exit logging and call je_sdallocx_impl() directly rather than the
je_sdallocx() wrapper, so it mirrors free_sized() and no longer logs under
sdallocx. The C++ sized-delete paths (sizedDeleteImpl, alignedSizedDeleteImpl)
get the same treatment: log entry/exit unconditionally and guard the call with
likely(ptr != nullptr).
This commit is contained in:
Bruno Gonçalves
2026-06-21 22:59:40 -03:00
committed by Slobodan Predolac
parent e8a0d2b477
commit 7ce8b9165d
4 changed files with 67 additions and 10 deletions

View File

@@ -231,12 +231,11 @@ operator delete[](void *ptr, const std::nothrow_t &) noexcept {
JEMALLOC_ALWAYS_INLINE
void
sizedDeleteImpl(void *ptr, std::size_t size) noexcept {
if (unlikely(ptr == nullptr)) {
return;
}
LOG("core.operator_delete.entry", "ptr: %p, size: %zu", ptr, size);
je_sdallocx_noflags(ptr, size);
if (likely(ptr != nullptr)) {
je_sdallocx_noflags(ptr, size);
}
LOG("core.operator_delete.exit", "");
}
@@ -262,13 +261,12 @@ alignedSizedDeleteImpl(
if (config_debug) {
assert(((size_t)alignment & ((size_t)alignment - 1)) == 0);
}
if (unlikely(ptr == nullptr)) {
return;
}
LOG("core.operator_delete.entry", "ptr: %p, size: %zu, alignment: %zu",
ptr, size, alignment);
je_sdallocx_impl(ptr, size, MALLOCX_ALIGN(alignment));
if (likely(ptr != nullptr)) {
je_sdallocx_impl(ptr, size, MALLOCX_ALIGN(alignment));
}
LOG("core.operator_delete.exit", "");
}