diff --git a/libc/upstream-dlmalloc/malloc.c b/libc/upstream-dlmalloc/malloc.c index 3c9d36bf4..a61c0da9c 100644 --- a/libc/upstream-dlmalloc/malloc.c +++ b/libc/upstream-dlmalloc/malloc.c @@ -4822,8 +4822,13 @@ void* dlcalloc(size_t n_elements, size_t elem_size) { req = MAX_SIZE_T; /* force downstream failure on overflow */ } mem = dlmalloc(req); - if (mem != 0 && calloc_must_clear(mem2chunk(mem))) - memset(mem, 0, req); + if (mem != 0) { + mchunkptr p = mem2chunk(mem); + if (calloc_must_clear(p)) { + /* Make sure to clear all of the buffer, not just the requested size. */ + memset(mem, 0, chunksize(p) - overhead_for(p)); + } + } return mem; } diff --git a/tests/malloc_test.cpp b/tests/malloc_test.cpp index b76625a7a..5af5a6fb5 100644 --- a/tests/malloc_test.cpp +++ b/tests/malloc_test.cpp @@ -372,3 +372,22 @@ TEST(malloc, malloc_info) { } #endif } + +TEST(malloc, calloc_usable_size) { + for (size_t size = 1; size <= 2048; size++) { + void* pointer = malloc(size); + ASSERT_TRUE(pointer != nullptr); + memset(pointer, 0xeb, malloc_usable_size(pointer)); + free(pointer); + + // We should get a previous pointer that has been set to non-zero. + // If calloc does not zero out all of the data, this will fail. + uint8_t* zero_mem = reinterpret_cast(calloc(1, size)); + ASSERT_TRUE(pointer != nullptr); + size_t usable_size = malloc_usable_size(zero_mem); + for (size_t i = 0; i < usable_size; i++) { + ASSERT_EQ(0, zero_mem[i]) << "Failed at allocation size " << size << " at byte " << i; + } + free(zero_mem); + } +}