Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions src/snmalloc/global/libc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<void**>(ptr_);
void* p = alloc(sz);
Expand Down
15 changes: 15 additions & 0 deletions src/test/func/malloc/malloc.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Loading