[Sanitizer][Darwin] Add interceptor for malloc_zone_from_ptr
authorJulian Lettner <jlettner@apple.com>
Fri, 9 Aug 2019 21:46:32 +0000 (21:46 +0000)
committerJulian Lettner <jlettner@apple.com>
Fri, 9 Aug 2019 21:46:32 +0000 (21:46 +0000)
Ensure that malloc_default_zone and malloc_zone_from_ptr return the
sanitizer-installed malloc zone even when MallocStackLogging (MSL) is
requested. This prevents crashes in certain situations. Note that the
sanitizers and MSL cannot be used together. If both are enabled, MSL
functionality is essentially deactivated since it only hooks the default
allocator which is replaced by a custom sanitizer allocator.

rdar://53686175

Reviewed By: kubamracek

Differential Revision: https://reviews.llvm.org/D65990

llvm-svn: 368492

compiler-rt/lib/sanitizer_common/sanitizer_malloc_mac.inc
compiler-rt/test/sanitizer_common/TestCases/Darwin/malloc_zone.cpp [new file with mode: 0644]

index 3f3581e..11adbe5 100644 (file)
@@ -91,6 +91,15 @@ INTERCEPTOR(malloc_zone_t *, malloc_default_zone, void) {
   return &sanitizer_zone;
 }
 
+INTERCEPTOR(malloc_zone_t *, malloc_zone_from_ptr, const void *ptr) {
+  COMMON_MALLOC_ENTER();
+  size_t size = sanitizer_zone.size(&sanitizer_zone, ptr);
+  if (size) { // Claimed by sanitizer zone?
+    return &sanitizer_zone;
+  }
+  return REAL(malloc_zone_from_ptr)(ptr);
+}
+
 INTERCEPTOR(malloc_zone_t *, malloc_default_purgeable_zone, void) {
   // FIXME: ASan should support purgeable allocations.
   // https://github.com/google/sanitizers/issues/139
@@ -226,7 +235,7 @@ void __sanitizer_mz_free(malloc_zone_t *zone, void *ptr) {
 }
 
 #define GET_ZONE_FOR_PTR(ptr) \
-  malloc_zone_t *zone_ptr = malloc_zone_from_ptr(ptr); \
+  malloc_zone_t *zone_ptr = WRAP(malloc_zone_from_ptr)(ptr); \
   const char *zone_name = (zone_ptr == 0) ? 0 : zone_ptr->zone_name
 
 extern "C"
diff --git a/compiler-rt/test/sanitizer_common/TestCases/Darwin/malloc_zone.cpp b/compiler-rt/test/sanitizer_common/TestCases/Darwin/malloc_zone.cpp
new file mode 100644 (file)
index 0000000..fd6ef03
--- /dev/null
@@ -0,0 +1,45 @@
+// Check that malloc_default_zone and malloc_zone_from_ptr return the
+// sanitizer-installed malloc zone even when MallocStackLogging (MSL) is
+// requested. This prevents crashes in certain situations. Note that the
+// sanitizers and MSL cannot be used together. If both are enabled, MSL
+// functionality is essentially deactivated since it only hooks the default
+// allocator which is replaced by a custom sanitizer allocator.
+//
+// MSL=lite creates its own special malloc zone, copies the passed zone name,
+// and leaks it.
+// RUN: echo "leak:create_and_insert_msl_lite_zone" >> lsan.supp
+//
+// RUN: %clangxx -g %s -o %t
+// RUN:                                                                   %run %t | FileCheck %s
+// RUN: %env MallocStackLogging=lite LSAN_OPTIONS=suppressions=lsan.supp  %run %t | FileCheck %s
+// RUN: %env MallocStackLogging=full                                      %run %t | FileCheck %s
+//
+// UBSan does not install a malloc zone.
+// XFAIL: ubsan
+//
+
+#include <malloc/malloc.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+int main(void) {
+  malloc_zone_t *default_zone = malloc_default_zone();
+  printf("default zone name: %s\n", malloc_get_zone_name(default_zone));
+// CHECK: default zone name: {{a|l|t}}san
+
+  void *ptr1 = malloc(10);
+  void *ptr2 = malloc_zone_malloc(default_zone, 10);
+
+  malloc_zone_t* zone1 = malloc_zone_from_ptr(ptr1);
+  malloc_zone_t* zone2 = malloc_zone_from_ptr(ptr2);
+
+  printf("zone1: %d\n", zone1 == default_zone);
+  printf("zone2: %d\n", zone2 == default_zone);
+// CHECK: zone1: 1
+// CHECK: zone2: 1
+
+  free(ptr1);
+  malloc_zone_free(zone2, ptr2);
+
+  return 0;
+}