Fix http://code.google.com/p/address-sanitizer/issues/detail?id=87 by making sure we replace the default CFAllocator only after __CFInitialize has been called.


git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@159749 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/asan/asan_mac.cc b/lib/asan/asan_mac.cc
index 2d5a967..f58852c 100644
--- a/lib/asan/asan_mac.cc
+++ b/lib/asan/asan_mac.cc
@@ -295,8 +295,6 @@
                                 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);
@@ -428,6 +426,12 @@
   }
 }
 
+DECLARE_REAL_AND_INTERCEPTOR(void, free, void *ptr)
+
+extern "C"
+void __CFInitialize();
+DECLARE_REAL_AND_INTERCEPTOR(void, __CFInitialize)
+
 namespace __asan {
 
 void InitializeMacInterceptors() {
@@ -453,6 +457,9 @@
   // Some of the library functions call free() directly, so we have to
   // intercept it.
   CHECK(INTERCEPT_FUNCTION(free));
+  if (FLAG_replace_cfallocator) {
+    CHECK(INTERCEPT_FUNCTION(__CFInitialize));
+  }
 }
 
 }  // namespace __asan
diff --git a/lib/asan/asan_malloc_mac.cc b/lib/asan/asan_malloc_mac.cc
index 0f510bf..75f7788 100644
--- a/lib/asan/asan_malloc_mac.cc
+++ b/lib/asan/asan_malloc_mac.cc
@@ -78,6 +78,21 @@
   }
 }
 
+// We can't always replace the default CFAllocator with cf_asan right in
+// ReplaceSystemMalloc(), because it is sometimes called before
+// __CFInitialize(), when the default allocator is invalid and replacing it may
+// crash the program. Instead we wait for the allocator to initialize and jump
+// in just after __CFInitialize(). Nobody is going to allocate memory using
+// CFAllocators before that, so we won't miss anything.
+//
+// See http://code.google.com/p/address-sanitizer/issues/detail?id=87
+// and http://opensource.apple.com/source/CF/CF-550.43/CFRuntime.c
+INTERCEPTOR(void, __CFInitialize) {
+  CHECK(FLAG_replace_cfallocator);
+  REAL(__CFInitialize)();
+  if (cf_asan) CFAllocatorSetDefault(cf_asan);
+}
+
 namespace {
 // TODO(glider): the mz_* functions should be united with the Linux wrappers,
 // as they are basically copied from there.
@@ -300,7 +315,7 @@
 
 }  // unnamed namespace
 
-extern bool kCFUseCollectableAllocator;  // is GC on?
+extern int __CFRuntimeClassTableSize;
 
 namespace __asan {
 void ReplaceSystemMalloc() {
@@ -377,7 +392,11 @@
           /*deallocate*/ &cf_free,
           /*preferredSize*/ 0 };
     cf_asan = CFAllocatorCreate(kCFAllocatorUseContext, &asan_context);
-    CFAllocatorSetDefault(cf_asan);
+    // If __CFInitialize() hasn't been called yet, cf_asan will be installed
+    // as the default allocator after __CFInitialize() finishes (see the
+    // interceptor for __CFInitialize() above). Otherwise (if
+    // __CFRuntimeClassTableSize is initialized) install cf_asan right now.
+    if (__CFRuntimeClassTableSize) CFAllocatorSetDefault(cf_asan);
   }
 }
 }  // namespace __asan