diff options
-rw-r--r-- | lib/asan/asan_mac.cc | 8 | ||||
-rw-r--r-- | lib/asan/asan_malloc_mac.cc | 36 | ||||
-rw-r--r-- | lib/asan/tests/asan_test.cc | 2 |
3 files changed, 35 insertions, 11 deletions
diff --git a/lib/asan/asan_mac.cc b/lib/asan/asan_mac.cc index f28b67181..ad3186d93 100644 --- a/lib/asan/asan_mac.cc +++ b/lib/asan/asan_mac.cc @@ -29,8 +29,9 @@ #include <sys/resource.h> #include <sys/sysctl.h> #include <sys/ucontext.h> -#include <pthread.h> #include <fcntl.h> +#include <pthread.h> +#include <stdlib.h> // for free() #include <unistd.h> #include <libkern/OSAtomic.h> #include <CoreFoundation/CFString.h> @@ -294,6 +295,8 @@ INTERCEPTOR(void, dispatch_async_f, dispatch_queue_t dq, void *ctxt, asan_dispatch_call_block_and_release); } +DECLARE_REAL_AND_INTERCEPTOR(void, free, void *ptr); + INTERCEPTOR(void, dispatch_sync_f, dispatch_queue_t dq, void *ctxt, dispatch_function_t func) { GET_STACK_TRACE_HERE(kStackTraceMax); @@ -447,6 +450,9 @@ void InitializeMacInterceptors() { // Until this problem is fixed we need to check that the string is // non-constant before calling CFStringCreateCopy. CHECK(INTERCEPT_FUNCTION(CFStringCreateCopy)); + // Some of the library functions call free() directly, so we have to + // intercept it. + CHECK(INTERCEPT_FUNCTION(free)); } } // namespace __asan diff --git a/lib/asan/asan_malloc_mac.cc b/lib/asan/asan_malloc_mac.cc index 7445c4677..111355825 100644 --- a/lib/asan/asan_malloc_mac.cc +++ b/lib/asan/asan_malloc_mac.cc @@ -30,12 +30,25 @@ // ---------------------- Replacement functions ---------------- {{{1 using namespace __asan; // NOLINT +// TODO(glider): do we need both zones? +static malloc_zone_t *system_malloc_zone = 0; +static malloc_zone_t *system_purgeable_zone = 0; +CFAllocatorRef cf_asan = 0; + // The free() implementation provided by OS X calls malloc_zone_from_ptr() // to find the owner of |ptr|. If the result is 0, an invalid free() is // reported. Our implementation falls back to asan_free() in this case // in order to print an ASan-style report. -extern "C" -void free(void *ptr) { +// +// For the objects created by _CFRuntimeCreateInstance a CFAllocatorRef is +// placed at the beginning of the allocated chunk and the pointer returned by +// our allocator is off by sizeof(CFAllocatorRef). This pointer can be then +// passed directly to free(), which will lead to errors. +// To overcome this we're checking whether |ptr-sizeof(CFAllocatorRef)| +// contains a pointer to our CFAllocator (assuming no other allocator is used). +// See http://code.google.com/p/address-sanitizer/issues/detail?id=70 for more +// info. +INTERCEPTOR(void, free, void *ptr) { malloc_zone_t *zone = malloc_zone_from_ptr(ptr); if (zone) { #if defined(MAC_OS_X_VERSION_10_6) && \ @@ -49,16 +62,22 @@ void free(void *ptr) { malloc_zone_free(zone, ptr); #endif } else { + if (FLAG_replace_cfallocator) { + // Make sure we're not hitting the previous page. This may be incorrect + // if ASan's malloc returns an address ending with 0xFF8, which will be + // then padded to a page boundary with a CFAllocatorRef. + uptr arith_ptr = (uptr)ptr; + if ((arith_ptr & 0xFFF) > sizeof(CFAllocatorRef)) { + CFAllocatorRef *saved = + (CFAllocatorRef*)(arith_ptr - sizeof(CFAllocatorRef)); + if ((*saved == cf_asan) && asan_mz_size(saved)) ptr = (void*)saved; + } + } GET_STACK_TRACE_HERE_FOR_FREE(ptr); asan_free(ptr, &stack); } } -// TODO(glider): do we need both zones? -static malloc_zone_t *system_malloc_zone = 0; -static malloc_zone_t *system_purgeable_zone = 0; - -// We need to provide wrappers around all the libc functions. namespace { // TODO(glider): the mz_* functions should be united with the Linux wrappers, // as they are basically copied from there. @@ -388,8 +407,7 @@ void ReplaceSystemMalloc() { /*reallocate*/ &cf_realloc, /*deallocate*/ &cf_free, /*preferredSize*/ 0 }; - CFAllocatorRef cf_asan = - CFAllocatorCreate(kCFAllocatorUseContext, &asan_context); + cf_asan = CFAllocatorCreate(kCFAllocatorUseContext, &asan_context); CFAllocatorSetDefault(cf_asan); } } diff --git a/lib/asan/tests/asan_test.cc b/lib/asan/tests/asan_test.cc index 80af8b0ad..89dbb1530 100644 --- a/lib/asan/tests/asan_test.cc +++ b/lib/asan/tests/asan_test.cc @@ -2053,7 +2053,7 @@ TEST(AddressSanitizerMac, NSObjectOOB) { // Make sure that correct pointer is passed to free() when deallocating a // NSURL object. // See http://code.google.com/p/address-sanitizer/issues/detail?id=70. -TEST(AddressSanitizerMac, DISABLED_NSURLDeallocation) { +TEST(AddressSanitizerMac, NSURLDeallocation) { TestNSURLDeallocation(); } #endif // __APPLE__ |