[compiler-rt] Add aligned_alloc to macOS tsan interceptors (PR #79198)

via llvm-commits llvm-commits at lists.llvm.org
Tue Jan 23 11:59:06 PST 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-compiler-rt-sanitizer

Author: Chris Apple (cjappl)

<details>
<summary>Changes</summary>

Directly following on the heels of the suggestion given in #<!-- -->77543 

Following the example in the tsan libdispatch interceptors (https://github.com/llvm/llvm-project/blob/f7669ba3d9443bc95dd63fa25beea13e6265fdc5/compiler-rt/lib/tsan/rtl/tsan_interceptors_libdispatch.cpp#L226-L247)

This PR forward declares `aligned_alloc` on systems that may not have it (like pre-10.15 OSX). There is a unit test provided to ensure this works as intended, which passes for me when I compile both with 

SANITIZER_MIN_OSX_VERSION:STRING=10.10
and 
SANITIZER_MIN_OSX_VERSION:STRING=14.0

This test is almost an exact copy of another tsan test, found [here](https://github.com/llvm/llvm-project/blob/main/compiler-rt/test/tsan/free_race.c).

To facilitate this in a more reusable way, a small refactor was done:
1. Removed SANITIZER_WEAK_IMPORT from [compiler-rt/lib/tsan/rtl/tsan_dispatch_defs.h](https://github.com/llvm/llvm-project/compare/main...cjappl:llvm-project:add_aligned_alloc?expand=1#diff-8178a9a7b2839ad0a02ed04254e674686e73750fbd7d274a6abf41cb3b80b83b). This was placed in sanitizer_common so it can be accessible by more sanitizers in the future.




---
Full diff: https://github.com/llvm/llvm-project/pull/79198.diff


4 Files Affected:

- (modified) compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h (+10-3) 
- (modified) compiler-rt/lib/tsan/rtl/tsan_dispatch_defs.h (-7) 
- (modified) compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp (+11-1) 
- (added) compiler-rt/test/tsan/free_race_aligned_alloc.c (+62) 


``````````diff
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h b/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h
index 3809669dd48bb3..75fda42a480a78 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h
@@ -33,15 +33,22 @@
 # define SANITIZER_INTERFACE_ATTRIBUTE __declspec(dllimport)
 #else
 # define SANITIZER_INTERFACE_ATTRIBUTE __declspec(dllexport)
-#endif
+#endif // SANITIZER_IMPORT_INTERFACE
 # define SANITIZER_WEAK_ATTRIBUTE
+# define  SANITIZER_WEAK_IMPORT
 #elif SANITIZER_GO
 # define SANITIZER_INTERFACE_ATTRIBUTE
 # define SANITIZER_WEAK_ATTRIBUTE
-#else
+# define SANITIZER_WEAK_IMPORT
+#else // NOT SANITIZER_WINDOWS
 # define SANITIZER_INTERFACE_ATTRIBUTE __attribute__((visibility("default")))
 # define SANITIZER_WEAK_ATTRIBUTE  __attribute__((weak))
-#endif
+#if SANITIZER_APPLE
+# define SANITIZER_WEAK_IMPORT extern "C" __attribute((weak_import))
+#else // NOT SANITIZER_APPLE
+# define SANITIZER_WEAK_IMPORT extern "C" SANITIZER_WEAK_ATTRIBUTE
+#endif // SANITIZER_APPLE
+#endif // SANITIZER_WINDOWS
 
 //--------------------------- WEAK FUNCTIONS ---------------------------------//
 // When working with weak functions, to simplify the code and make it more
diff --git a/compiler-rt/lib/tsan/rtl/tsan_dispatch_defs.h b/compiler-rt/lib/tsan/rtl/tsan_dispatch_defs.h
index 54c0b0ba4b409a..8d38beb0b0a209 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_dispatch_defs.h
+++ b/compiler-rt/lib/tsan/rtl/tsan_dispatch_defs.h
@@ -56,13 +56,6 @@ extern const dispatch_block_t _dispatch_data_destructor_munmap;
 # define DISPATCH_NOESCAPE
 #endif
 
-#if SANITIZER_APPLE
-# define SANITIZER_WEAK_IMPORT extern "C" __attribute((weak_import))
-#else
-# define SANITIZER_WEAK_IMPORT extern "C" __attribute((weak))
-#endif
-
-
 // Data types used in dispatch APIs
 typedef unsigned long size_t;
 typedef unsigned long uintptr_t;
diff --git a/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp b/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp
index a9f6673ac44e90..1e27807e26a498 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp
+++ b/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp
@@ -14,6 +14,7 @@
 
 #include "sanitizer_common/sanitizer_atomic.h"
 #include "sanitizer_common/sanitizer_errno.h"
+#include "sanitizer_common/sanitizer_internal_defs.h"
 #include "sanitizer_common/sanitizer_libc.h"
 #include "sanitizer_common/sanitizer_linux.h"
 #include "sanitizer_common/sanitizer_platform_limits_netbsd.h"
@@ -815,14 +816,23 @@ TSAN_INTERCEPTOR(void*, memalign, uptr align, uptr sz) {
 #define TSAN_MAYBE_INTERCEPT_MEMALIGN
 #endif
 
-#if !SANITIZER_APPLE
+// aligned_alloc was introduced in macOS 10.15
+// Linking will fail when using an older SDK
+#if !SANITIZER_APPLE || defined(__MAC_10_15)
+// macOS 10.15 is greater than our minimal deployment target.  To ensure we
+// generate a weak reference so the TSan dylib continues to work on older
+// systems, we need to forward declare the intercepted function as "weak
+// imports".   
+SANITIZER_WEAK_IMPORT void *aligned_alloc(SIZE_T __alignment, SIZE_T __size);
 TSAN_INTERCEPTOR(void*, aligned_alloc, uptr align, uptr sz) {
   if (in_symbolizer())
     return InternalAlloc(sz, nullptr, align);
   SCOPED_INTERCEPTOR_RAW(aligned_alloc, align, sz);
   return user_aligned_alloc(thr, pc, align, sz);
 }
+#endif
 
+#if !SANITIZER_APPLE
 TSAN_INTERCEPTOR(void*, valloc, uptr sz) {
   if (in_symbolizer())
     return InternalAlloc(sz, nullptr, GetPageSizeCached());
diff --git a/compiler-rt/test/tsan/free_race_aligned_alloc.c b/compiler-rt/test/tsan/free_race_aligned_alloc.c
new file mode 100644
index 00000000000000..5e9c496925cb19
--- /dev/null
+++ b/compiler-rt/test/tsan/free_race_aligned_alloc.c
@@ -0,0 +1,62 @@
+// RUN: %clang_tsan -O1 %s -o %t -undefined dynamic_lookup
+// RUN: %deflake %run %t | FileCheck %s 
+
+#include "test.h"
+
+#include <stdlib.h>
+
+#if defined(__cplusplus) && (__cplusplus >= 201703L)
+#define HAVE_ALIGNED_ALLOC 1
+#endif
+
+#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \
+    __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101500
+#define HAVE_ALIGNED_ALLOC 0 
+#else
+#endif
+
+
+int *mem;
+pthread_mutex_t mtx;
+
+void *Thread1(void *x) {
+  pthread_mutex_lock(&mtx);
+  free(mem);
+  pthread_mutex_unlock(&mtx);
+  barrier_wait(&barrier);
+  return NULL;
+}
+
+__attribute__((noinline)) void *Thread2(void *x) {
+  barrier_wait(&barrier);
+  pthread_mutex_lock(&mtx);
+  mem[0] = 42;
+  pthread_mutex_unlock(&mtx);
+  return NULL;
+}
+
+int main() {
+
+  barrier_init(&barrier, 2);
+#if HAVE_ALIGNED_ALLOC
+  mem = (int*)aligned_alloc(8, 8);
+#else
+  mem = (int*)malloc(8);
+#endif
+  pthread_mutex_init(&mtx, 0);
+  pthread_t t;
+  pthread_create(&t, NULL, Thread1, NULL);
+  Thread2(0);
+  pthread_join(t, NULL);
+  pthread_mutex_destroy(&mtx);
+  return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: heap-use-after-free
+// CHECK:   Write of size 4 at {{.*}} by main thread{{.*}}:
+// CHECK:     #0 Thread2
+// CHECK:     #1 main
+// CHECK:   Previous write of size 8 at {{.*}} by thread T1{{.*}}:
+// CHECK:     #0 free
+// CHECK:     #{{(1|2)}} Thread1
+// CHECK: SUMMARY: ThreadSanitizer: heap-use-after-free{{.*}}Thread2

``````````

</details>


https://github.com/llvm/llvm-project/pull/79198


More information about the llvm-commits mailing list