Index: lib/asan/asan_malloc_linux.cc =================================================================== --- lib/asan/asan_malloc_linux.cc +++ lib/asan/asan_malloc_linux.cc @@ -26,13 +26,25 @@ // ---------------------- Replacement functions ---------------- {{{1 using namespace __asan; // NOLINT +static const uptr kCallocPoolSize = 1024; +static uptr calloc_memory_for_dlsym[kCallocPoolSize]; + +static bool IsInCallocPool(const void *ptr) { + sptr off = (sptr)calloc_memory_for_dlsym - (sptr)ptr; + return 0 <= off && off < (sptr)kCallocPoolSize; +} + INTERCEPTOR(void, free, void *ptr) { GET_STACK_TRACE_FREE; + if (IsInCallocPool(ptr)) + return; asan_free(ptr, &stack, FROM_MALLOC); } INTERCEPTOR(void, cfree, void *ptr) { GET_STACK_TRACE_FREE; + if (IsInCallocPool(ptr)) + return; asan_free(ptr, &stack, FROM_MALLOC); } @@ -44,8 +56,6 @@ INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) { if (UNLIKELY(!asan_inited)) { // Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym. - const uptr kCallocPoolSize = 1024; - static uptr calloc_memory_for_dlsym[kCallocPoolSize]; static uptr allocated; uptr size_in_words = ((nmemb * size) + kWordSize - 1) / kWordSize; void *mem = (void*)&calloc_memory_for_dlsym[allocated]; @@ -59,6 +69,13 @@ INTERCEPTOR(void*, realloc, void *ptr, uptr size) { GET_STACK_TRACE_MALLOC; + if (IsInCallocPool(ptr)) { + uptr offset = (uptr)calloc_memory_for_dlsym - (uptr)ptr; + uptr copy_size = Min(size, kCallocPoolSize - offset); + void *new_ptr = asan_malloc(size, &stack); + internal_memcpy(new_ptr, ptr, copy_size); + return new_ptr; + } return asan_realloc(ptr, size, &stack); } Index: test/asan/TestCases/Linux/calloc-preload.c =================================================================== --- /dev/null +++ test/asan/TestCases/Linux/calloc-preload.c @@ -0,0 +1,36 @@ +// Test that initially callocked memory is properly freed +// (see https://github.com/google/sanitizers/issues/626). +// +// RUN: %clang %s -o %t +// RUN: env LD_PRELOAD=%shared_libasan %run %t +// +// REQUIRES: asan-dynamic-runtime +// +// This way of setting LD_PRELOAD does not work with Android test runner. +// REQUIRES: not-android + +#include +#include + +static void *ptr; + +// This constructor will run before __asan_init +// so calloc will allocate memory from special pool. +static void init() { + ptr = calloc(10, 1); +} + +__attribute__((section(".preinit_array"), used)) +void *dummy = init; + +void free_memory() { + // This used to abort because + // Asan's free didn't recognize ptr. + free(ptr); +} + +int main() { + free_memory(); + return 0; +} +