Index: lib/asan/asan_allocator.cc =================================================================== --- lib/asan/asan_allocator.cc +++ lib/asan/asan_allocator.cc @@ -22,6 +22,7 @@ #include "asan_stack.h" #include "asan_thread.h" #include "sanitizer_common/sanitizer_allocator_interface.h" +#include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_internal_defs.h" #include "sanitizer_common/sanitizer_list.h" @@ -523,6 +524,8 @@ uptr chunk_beg = p - kChunkHeaderSize; AsanChunk *m = reinterpret_cast(chunk_beg); + if (!IsAccessibleMemoryRange((uptr)m, sizeof(AsanChunk))) + ReportFreeNotMalloced((uptr)ptr, stack); if (delete_size && flags()->new_delete_type_mismatch && delete_size != m->UsedSize()) { ReportNewDeleteSizeMismatch(p, delete_size, stack); @@ -539,6 +542,8 @@ uptr p = reinterpret_cast(old_ptr); uptr chunk_beg = p - kChunkHeaderSize; AsanChunk *m = reinterpret_cast(chunk_beg); + if (!IsAccessibleMemoryRange((uptr)m, sizeof(AsanChunk))) + ReportFreeNotMalloced((uptr)old_ptr, stack); AsanStats &thread_stats = GetCurrentThreadStats(); thread_stats.reallocs++; Index: test/asan/TestCases/Posix/bad-free-no-segv.cc =================================================================== --- /dev/null +++ test/asan/TestCases/Posix/bad-free-no-segv.cc @@ -0,0 +1,31 @@ +// RUN: %clangxx_asan -O0 %s -o %t +// RUN: not %run %t f 2>&1 | FileCheck %s +// RUN: not %run %t r 2>&1 | FileCheck %s +#include +#include +#include + +// CHECK-NOT: DEADLYSIGNAL +// CHECK: AddressSanitizer: attempting free on address which was not malloc()-ed +int main(int argc, char **argv) { + // The shadow gap is mprotect()ed, so we get an address inside it and pass it + // along to free. reading from it should be a problem and ASan should notice + // it before trying to read. + size_t shadow_scale, shadow_offset; + __asan_get_shadow_mapping(&shadow_scale, &shadow_offset); + // We add 0x100 because asan_free subtracts sizeof(AsanChunk) to our ptr. + // Which means we need to make sure that the free()ed/realloc()ed pointer is + // also in non-addressable memory. + void *p = (void *)(shadow_offset + 0x1000 + (shadow_offset >> shadow_scale)); + assert(argc == 2); + switch (argv[1][0]) { + case 'f': + free(p); + break; + case 'r': + realloc(p, 42); + break; + default: + assert(false); + } +}