summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/asan/asan_mac.cc8
-rw-r--r--lib/asan/asan_malloc_mac.cc36
-rw-r--r--lib/asan/tests/asan_test.cc2
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__