From c067e5fbd538fa9e285805af449911c6540df53a Mon Sep 17 00:00:00 2001 From: David Carlier Date: Fri, 26 Jun 2026 22:06:56 +0100 Subject: [PATCH] reallocarr overflow check ordering fix. check the overflow flag before the zero-size early return, otherwise an overflow truncating to zero is wrongly reported as success. --- src/snmalloc/global/libc.h | 8 ++++---- src/test/func/malloc/malloc.cc | 15 +++++++++++++++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/snmalloc/global/libc.h b/src/snmalloc/global/libc.h index a8e1b09e8..caa61f010 100644 --- a/src/snmalloc/global/libc.h +++ b/src/snmalloc/global/libc.h @@ -153,15 +153,15 @@ namespace snmalloc::libc int err = errno; bool overflow = false; size_t sz = bits::umul(size, nmemb, overflow); + if (SNMALLOC_UNLIKELY(overflow)) + { + return set_error_and_return(EOVERFLOW); + } if (SNMALLOC_UNLIKELY(sz == 0)) { errno = err; return 0; } - if (SNMALLOC_UNLIKELY(overflow)) - { - return set_error_and_return(EOVERFLOW); - } void** ptr = reinterpret_cast(ptr_); void* p = alloc(sz); diff --git a/src/test/func/malloc/malloc.cc b/src/test/func/malloc/malloc.cc index 3dcfb4559..b77f389bb 100644 --- a/src/test/func/malloc/malloc.cc +++ b/src/test/func/malloc/malloc.cc @@ -338,6 +338,21 @@ int main(int argc, char** argv) test_reallocarr((size_t)~0, 1, 0, SUCCESS, false); test_reallocarr((size_t)~0, 1, 16, SUCCESS, false); + // reallocarr must report EOVERFLOW when nmemb*size overflows, even when the + // truncated product is exactly zero. half*half is 2^BITS on 32- and 64-bit. + { + const size_t half = bits::one_at_bit(bits::BITS / 2); + void* p = testlib_malloc(16); + EXPECT(p != nullptr, "reallocarr overflow: alloc failed\n"); + errno = SUCCESS; + int r = testlib_reallocarr(&p, half, half); + EXPECT( + r == EOVERFLOW, "reallocarr overflow: expected EOVERFLOW got {}\n", r); + // p must be left untouched on overflow. + EXPECT(p != nullptr, "reallocarr overflow: ptr should be unchanged\n"); + testlib_free(p); + } + for (smallsizeclass_t sc(0); sc < (MAX_SMALL_SIZECLASS_BITS + 4); sc++) { const size_t size = bits::one_at_bit(sc);