Intercept CFAllocator for each thread in the program.
Test that child threads use the ASan allocator, that allocated memory can be passed to another thread and deallocated on it.
This should fix http://code.google.com/p/address-sanitizer/issues/detail?id=81


git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@160630 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/asan/asan_internal.h b/lib/asan/asan_internal.h
index 4f6d9e3..8c1f320 100644
--- a/lib/asan/asan_internal.h
+++ b/lib/asan/asan_internal.h
@@ -107,6 +107,7 @@
 void SetAlternateSignalStack();
 void UnsetAlternateSignalStack();
 void InstallSignalHandlers();
+void AsanPlatformThreadInit();
 
 // Wrapper for TLS/TSD.
 void AsanTSDInit(void (*destructor)(void *tsd));
diff --git a/lib/asan/asan_linux.cc b/lib/asan/asan_linux.cc
index 0bb2bf4..9a3d6bd 100644
--- a/lib/asan/asan_linux.cc
+++ b/lib/asan/asan_linux.cc
@@ -72,6 +72,10 @@
   return signum == SIGSEGV && flags()->handle_segv;
 }
 
+void AsanPlatformThreadInit() {
+  // Nothing here for now.
+}
+
 AsanLock::AsanLock(LinkerInitialized) {
   // We assume that pthread_mutex_t initialized to all zeroes is a valid
   // unlocked mutex. We can not use PTHREAD_MUTEX_INITIALIZER as it triggers
diff --git a/lib/asan/asan_mac.cc b/lib/asan/asan_mac.cc
index 3527d9a..973fe88 100644
--- a/lib/asan/asan_mac.cc
+++ b/lib/asan/asan_mac.cc
@@ -92,6 +92,10 @@
   return (signum == SIGSEGV || signum == SIGBUS) && flags()->handle_segv;
 }
 
+void AsanPlatformThreadInit() {
+  ReplaceCFAllocator();
+}
+
 AsanLock::AsanLock(LinkerInitialized) {
   // We assume that OS_SPINLOCK_INIT is zero
 }
diff --git a/lib/asan/asan_mac.h b/lib/asan/asan_mac.h
index e3412bd..6c65765 100644
--- a/lib/asan/asan_mac.h
+++ b/lib/asan/asan_mac.h
@@ -46,6 +46,7 @@
 namespace __asan {
 
 int GetMacosVersion();
+void ReplaceCFAllocator();
 
 }  // namespace __asan
 
diff --git a/lib/asan/asan_malloc_mac.cc b/lib/asan/asan_malloc_mac.cc
index fc9adff..1a6c840 100644
--- a/lib/asan/asan_malloc_mac.cc
+++ b/lib/asan/asan_malloc_mac.cc
@@ -336,8 +336,10 @@
         /*reallocate*/ &cf_realloc,
         /*deallocate*/ &cf_free,
         /*preferredSize*/ 0 };
-  cf_asan = CFAllocatorCreate(kCFAllocatorUseContext, &asan_context);
-  CFAllocatorSetDefault(cf_asan);
+  if (!cf_asan)
+    cf_asan = CFAllocatorCreate(kCFAllocatorUseContext, &asan_context);
+  if (CFAllocatorGetDefault() != cf_asan)
+    CFAllocatorSetDefault(cf_asan);
 }
 
 void ReplaceSystemMalloc() {
diff --git a/lib/asan/asan_thread.cc b/lib/asan/asan_thread.cc
index a46ae28..05a41ea 100644
--- a/lib/asan/asan_thread.cc
+++ b/lib/asan/asan_thread.cc
@@ -89,6 +89,7 @@
            stack_top_ - stack_bottom_, &local);
   }
   fake_stack_.Init(stack_size());
+  AsanPlatformThreadInit();
 }
 
 thread_return_t AsanThread::ThreadStart() {
diff --git a/lib/asan/asan_win.cc b/lib/asan/asan_win.cc
index 9279dc6..9e899d5 100644
--- a/lib/asan/asan_win.cc
+++ b/lib/asan/asan_win.cc
@@ -172,6 +172,10 @@
   // FIXME: Decide what to do on Windows.
 }
 
+void AsanPlatformThreadInit() {
+  // Nothing here for now.
+}
+
 }  // namespace __asan
 
 #endif  // _WIN32
diff --git a/lib/asan/tests/asan_mac_test.h b/lib/asan/tests/asan_mac_test.h
index 2b194d0..441547a 100644
--- a/lib/asan/tests/asan_mac_test.h
+++ b/lib/asan/tests/asan_mac_test.h
@@ -15,4 +15,5 @@
   void TestGCDGroupAsync();
   void TestOOBNSObjects();
   void TestNSURLDeallocation();
+  void TestPassCFMemoryToAnotherThread();
 }
diff --git a/lib/asan/tests/asan_test.cc b/lib/asan/tests/asan_test.cc
index 2b0def9..8e967e9 100644
--- a/lib/asan/tests/asan_test.cc
+++ b/lib/asan/tests/asan_test.cc
@@ -1906,10 +1906,41 @@
   pthread_join(child, NULL);  // Shouldn't be reached.
 }
 
-TEST(AddressSanitizerMac, DISABLED_CFAllocatorDefaultDoubleFree_ChildPhread) {
+TEST(AddressSanitizerMac, CFAllocatorDefaultDoubleFree_ChildPhread) {
   EXPECT_DEATH(CFAllocator_DoubleFreeOnPthread(), "attempting double-free");
 }
 
+namespace {
+
+void *GLOB;
+
+void *CFAllocatorAllocateToGlob(void *unused) {
+  GLOB = CFAllocatorAllocate(NULL, 100, /*hint*/0);
+  return NULL;
+}
+
+void *CFAllocatorDeallocateFromGlob(void *unused) {
+  char *p = (char*)GLOB;
+  p[100] = 'A';  // ASan should report an error here.
+  CFAllocatorDeallocate(NULL, GLOB);
+  return NULL;
+}
+
+void CFAllocator_PassMemoryToAnotherThread() {
+  pthread_t th1, th2;
+  pthread_create(&th1, NULL, CFAllocatorAllocateToGlob, NULL);
+  pthread_join(th1, NULL);
+  pthread_create(&th2, NULL, CFAllocatorDeallocateFromGlob, NULL);
+  pthread_join(th2, NULL);
+}
+
+TEST(AddressSanitizerMac, CFAllocator_PassMemoryToAnotherThread) {
+  EXPECT_DEATH(CFAllocator_PassMemoryToAnotherThread(),
+               "heap-buffer-overflow");
+}
+
+}  // namespace
+
 // TODO(glider): figure out whether we still need these tests. Is it correct
 // to intercept the non-default CFAllocators?
 TEST(AddressSanitizerMac, DISABLED_CFAllocatorSystemDefaultDoubleFree) {