diff options
-rw-r--r-- | compiler-rt/lib/asan/asan_allocator2.cc | 18 | ||||
-rw-r--r-- | compiler-rt/lib/asan/lit_tests/free_hook_realloc.cc | 18 | ||||
-rw-r--r-- | compiler-rt/lib/asan/lit_tests/malloc_hook.cc | 16 | ||||
-rw-r--r-- | compiler-rt/lib/asan/tests/asan_test.cc | 18 |
4 files changed, 51 insertions, 19 deletions
diff --git a/compiler-rt/lib/asan/asan_allocator2.cc b/compiler-rt/lib/asan/asan_allocator2.cc index 8dacf67d798..b9d544aefdb 100644 --- a/compiler-rt/lib/asan/asan_allocator2.cc +++ b/compiler-rt/lib/asan/asan_allocator2.cc @@ -452,12 +452,6 @@ static void QuarantineChunk(AsanChunk *m, void *ptr, StackTrace *stack, AllocType alloc_type) { CHECK_EQ(m->chunk_state, CHUNK_QUARANTINE); - // FIXME: if the free hook produces an ASan report (e.g. due to a bug), - // printing the report may crash as the AsanChunk free-related fields have not - // been updated yet. We might need to introduce yet another chunk state to - // handle this correctly, but don't want to yet. - ASAN_FREE_HOOK(ptr); - if (m->alloc_type != alloc_type && flags()->alloc_dealloc_mismatch) ReportAllocTypeMismatch((uptr)ptr, stack, (AllocType)m->alloc_type, (AllocType)alloc_type); @@ -502,6 +496,7 @@ static void Deallocate(void *ptr, StackTrace *stack, AllocType alloc_type) { uptr chunk_beg = p - kChunkHeaderSize; AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg); + ASAN_FREE_HOOK(ptr); // Must mark the chunk as quarantined before any changes to its metadata. AtomicallySetQuarantineFlag(m, ptr, stack); QuarantineChunk(m, ptr, stack, alloc_type); @@ -517,17 +512,14 @@ static void *Reallocate(void *old_ptr, uptr new_size, StackTrace *stack) { thread_stats.reallocs++; thread_stats.realloced += new_size; - // Must mark the chunk as quarantined before any changes to its metadata. - // This also ensures that other threads can't deallocate it in the meantime. - AtomicallySetQuarantineFlag(m, old_ptr, stack); - - uptr old_size = m->UsedSize(); - uptr memcpy_size = Min(new_size, old_size); void *new_ptr = Allocate(new_size, 8, stack, FROM_MALLOC, true); if (new_ptr) { CHECK_NE(REAL(memcpy), (void*)0); + uptr memcpy_size = Min(new_size, m->UsedSize()); + // If realloc() races with free(), we may start copying freed memory. + // However, we will report racy double-free later anyway. REAL(memcpy)(new_ptr, old_ptr, memcpy_size); - QuarantineChunk(m, old_ptr, stack, FROM_MALLOC); + Deallocate(old_ptr, stack, FROM_MALLOC); } return new_ptr; } diff --git a/compiler-rt/lib/asan/lit_tests/free_hook_realloc.cc b/compiler-rt/lib/asan/lit_tests/free_hook_realloc.cc new file mode 100644 index 00000000000..5f678e6dc01 --- /dev/null +++ b/compiler-rt/lib/asan/lit_tests/free_hook_realloc.cc @@ -0,0 +1,18 @@ +// Check that free hook doesn't conflict with Realloc. +// RUN: %clangxx_asan -O2 %s -o %t && %t +#include <assert.h> +#include <stdlib.h> + +extern "C" { +void __asan_free_hook(void *ptr) { + *(int*)ptr = 0; +} +} + +int main() { + int *x = (int*)malloc(100); + x[0] = 42; + int *y = (int*)realloc(x, 200); + assert(y[0] == 42); + return 0; +} diff --git a/compiler-rt/lib/asan/lit_tests/malloc_hook.cc b/compiler-rt/lib/asan/lit_tests/malloc_hook.cc index 6435d105ee2..83be1020ea4 100644 --- a/compiler-rt/lib/asan/lit_tests/malloc_hook.cc +++ b/compiler-rt/lib/asan/lit_tests/malloc_hook.cc @@ -4,19 +4,31 @@ #include <unistd.h> extern "C" { +bool __asan_get_ownership(const void *p); + +void *global_ptr; + // Note: avoid calling functions that allocate memory in malloc/free // to avoid infinite recursion. void __asan_malloc_hook(void *ptr, size_t sz) { - write(1, "MallocHook\n", sizeof("MallocHook\n")); + if (__asan_get_ownership(ptr)) { + write(1, "MallocHook\n", sizeof("MallocHook\n")); + global_ptr = ptr; + } } void __asan_free_hook(void *ptr) { - write(1, "FreeHook\n", sizeof("FreeHook\n")); + if (__asan_get_ownership(ptr) && ptr == global_ptr) + write(1, "FreeHook\n", sizeof("FreeHook\n")); } } // extern "C" int main() { volatile int *x = new int; // CHECK: MallocHook + // Check that malloc hook was called with correct argument. + if (global_ptr != (void*)x) { + _exit(1); + } *x = 0; delete x; // CHECK: FreeHook diff --git a/compiler-rt/lib/asan/tests/asan_test.cc b/compiler-rt/lib/asan/tests/asan_test.cc index 5ae525de987..6071dce66a8 100644 --- a/compiler-rt/lib/asan/tests/asan_test.cc +++ b/compiler-rt/lib/asan/tests/asan_test.cc @@ -227,16 +227,26 @@ TEST(AddressSanitizer, BitFieldNegativeTest) { delete Ident(x); } +static size_t kOOMAllocationSize = + SANITIZER_WORDSIZE == 64 ? (size_t)(1ULL << 48) : (0xf0000000); + TEST(AddressSanitizer, OutOfMemoryTest) { - size_t size = SANITIZER_WORDSIZE == 64 ? (size_t)(1ULL << 48) : (0xf0000000); - EXPECT_EQ(0, realloc(0, size)); + EXPECT_EQ(0, realloc(0, kOOMAllocationSize)); EXPECT_EQ(0, realloc(0, ~Ident(0))); - EXPECT_EQ(0, malloc(size)); + EXPECT_EQ(0, malloc(kOOMAllocationSize)); EXPECT_EQ(0, malloc(~Ident(0))); - EXPECT_EQ(0, calloc(1, size)); + EXPECT_EQ(0, calloc(1, kOOMAllocationSize)); EXPECT_EQ(0, calloc(1, ~Ident(0))); } +TEST(AddressSanitizer, BadReallocTest) { + int *a = (int*)Ident(malloc(100)); + a[0] = 42; + EXPECT_EQ(0, realloc(a, kOOMAllocationSize)); + EXPECT_EQ(42, a[0]); + free(a); +} + #if ASAN_NEEDS_SEGV namespace { |