From d119945a4519a340707f8477495aa3048bb30a8f Mon Sep 17 00:00:00 2001 From: Feuris Date: Mon, 12 Oct 2026 00:06:30 -0300 Subject: [PATCH] fix(libc): allocate from realloc(NULL, 0) as malloc(0) does realloc(NULL, 0) returned NULL without allocating anything, while malloc(0) returns a unique pointer. C11 7.22.3.5p3 says realloc with a null pointer behaves like malloc for the specified size, so code that grows an empty buffer from zero elements (p = realloc(p, n * size) with n == 0) and treats NULL as out of memory failed on its first call. FreeBSD 11.4 never returns NULL from realloc for a zero size; je_realloc rounds the size up before choosing between resizing and allocating (contrib/jemalloc/src/jemalloc.c, je_realloc). A null pointer with size 0 now reaches the allocator's realloc, which allocates as malloc(0) does. A non-null pointer with size 0 is still freed and NULL returned, as before. Co-authored-by: milescoviello --- core/libs/prx/libc/src/ApplicationHeap.cpp | 2 +- core/libs/tests/ApplicationHeap.cpp | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/core/libs/prx/libc/src/ApplicationHeap.cpp b/core/libs/prx/libc/src/ApplicationHeap.cpp index f05e94132..e619429ee 100644 --- a/core/libs/prx/libc/src/ApplicationHeap.cpp +++ b/core/libs/prx/libc/src/ApplicationHeap.cpp @@ -176,7 +176,7 @@ void ApplicationHeapFree_nid_no_patch(void* pointer) { } void* ApplicationHeapReallocate_nid_no_patch(void* pointer, std::size_t bytes) { - if (bytes == 0) { + if (bytes == 0 && pointer != nullptr) { ApplicationHeapFree_nid_no_patch(pointer); return nullptr; } diff --git a/core/libs/tests/ApplicationHeap.cpp b/core/libs/tests/ApplicationHeap.cpp index 04adba57c..d7f755740 100644 --- a/core/libs/tests/ApplicationHeap.cpp +++ b/core/libs/tests/ApplicationHeap.cpp @@ -167,6 +167,12 @@ int main(int argc, char** argv) { reject([pointer] { ApplicationHeapUsableSize_nid_no_patch(pointer); }); *__error_nid_postfix() = 0; require(reallocf_nid_postfix(nullptr, SIZE_MAX) == nullptr && *__error_nid_postfix() == 12); + void* empty = ApplicationHeapAllocate_nid_no_patch(0); + require(empty != nullptr); + ApplicationHeapFree_nid_no_patch(empty); + empty = ApplicationHeapReallocate_nid_no_patch(nullptr, 0); + require(empty != nullptr); + ApplicationHeapFree_nid_no_patch(empty); for (std::size_t alignment : {16, 64, 4096}) { auto* aligned = ApplicationHeapAlign_nid_no_patch(alignment, 37); require(reinterpret_cast(aligned) % alignment == 0);