diff --git a/compiler-rt/lib/lsan/lsan_allocator.cpp b/compiler-rt/lib/lsan/lsan_allocator.cpp --- a/compiler-rt/lib/lsan/lsan_allocator.cpp +++ b/compiler-rt/lib/lsan/lsan_allocator.cpp @@ -123,14 +123,18 @@ void *Reallocate(const StackTrace &stack, void *p, uptr new_size, uptr alignment) { - RegisterDeallocation(p); if (new_size > max_malloc_size) { - allocator.Deallocate(GetAllocatorCache(), p); - return ReportAllocationSizeTooBig(new_size, stack); + ReportAllocationSizeTooBig(new_size, stack); + return nullptr; } - p = allocator.Reallocate(GetAllocatorCache(), p, new_size, alignment); - RegisterAllocation(stack, p, new_size); - return p; + RegisterDeallocation(p); + void *new_p = + allocator.Reallocate(GetAllocatorCache(), p, new_size, alignment); + if (new_p) + RegisterAllocation(stack, new_p, new_size); + else if (new_size != 0) + RegisterAllocation(stack, p, new_size); + return new_p; } void GetAllocatorCacheRange(uptr *begin, uptr *end) { diff --git a/compiler-rt/test/lsan/TestCases/malloc_zero.c b/compiler-rt/test/lsan/TestCases/malloc_zero.c new file mode 100644 --- /dev/null +++ b/compiler-rt/test/lsan/TestCases/malloc_zero.c @@ -0,0 +1,20 @@ +// RUN: %clang_lsan %s -o %t +// RUN: %env_lsan_opts=use_stacks=0 not %run %t 2>&1 | FileCheck %s + +#include +#include + +// CHECK: {{Leak|Address}}Sanitizer: detected memory leaks +// CHECK: {{Leak|Address}}Sanitizer: 1 byte(s) leaked in 1 allocation(s). + +__attribute__((noinline)) +void test() { + // The behavior of malloc(0) is implementation-defined. + char *p = malloc(0); + fprintf(stderr, "zero: %p\n", p); + p = 0; +} + +int main() { + test(); +} diff --git a/compiler-rt/test/lsan/TestCases/realloc_too_big.c b/compiler-rt/test/lsan/TestCases/realloc_too_big.c new file mode 100644 --- /dev/null +++ b/compiler-rt/test/lsan/TestCases/realloc_too_big.c @@ -0,0 +1,23 @@ +// RUN: %clang_lsan %s -o %t +// RUN: %env_lsan_opts=allocator_may_return_null=1:max_allocation_size_mb=1 not %run %t 2>&1 | FileCheck %s + +#include +#include +#include + +// CHECK: {{Leak|Address}}Sanitizer failed to allocate 0x100001 bytes + +// CHECK: {{Leak|Address}}Sanitizer: detected memory leaks +// CHECK: {{Leak|Address}}Sanitizer: 9 byte(s) leaked in 1 allocation(s). + +__attribute__((noinline)) +void test() { + char *p = malloc(9); + fprintf(stderr, "nine: %p\n", p); + assert(realloc(p, 0x100001) == NULL); // 1MiB+1 + p = 0; +} + +int main() { + test(); +} diff --git a/compiler-rt/test/lsan/TestCases/realloc_zero.c b/compiler-rt/test/lsan/TestCases/realloc_zero.c new file mode 100644 --- /dev/null +++ b/compiler-rt/test/lsan/TestCases/realloc_zero.c @@ -0,0 +1,12 @@ +// RUN: %clang_lsan %s -o %t +// RUN: %run %t + +#include +#include + +int main() { + char *p = malloc(1); + // The behavior of realloc(p, 0) is implementation-defined. + // We free the allocation. + assert(realloc(p, 0) == NULL); +}