diff --git a/compiler-rt/lib/tsan/rtl/tsan_dispatch_defs.h b/compiler-rt/lib/tsan/rtl/tsan_dispatch_defs.h --- a/compiler-rt/lib/tsan/rtl/tsan_dispatch_defs.h +++ b/compiler-rt/lib/tsan/rtl/tsan_dispatch_defs.h @@ -51,11 +51,18 @@ #define DISPATCH_DATA_DESTRUCTOR_MUNMAP _dispatch_data_destructor_munmap #if __has_attribute(noescape) - #define DISPATCH_NOESCAPE __attribute__((__noescape__)) +# define DISPATCH_NOESCAPE __attribute__((__noescape__)) #else - #define DISPATCH_NOESCAPE +# define DISPATCH_NOESCAPE #endif +#if SANITIZER_MAC +# 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_libdispatch.cpp b/compiler-rt/lib/tsan/rtl/tsan_interceptors_libdispatch.cpp --- a/compiler-rt/lib/tsan/rtl/tsan_interceptors_libdispatch.cpp +++ b/compiler-rt/lib/tsan/rtl/tsan_interceptors_libdispatch.cpp @@ -19,6 +19,10 @@ #include "BlocksRuntime/Block.h" #include "tsan_dispatch_defs.h" +#if SANITIZER_MAC +# include +#endif + namespace __tsan { typedef u16 uint16_t; @@ -219,8 +223,23 @@ DISPATCH_INTERCEPT(dispatch, false) DISPATCH_INTERCEPT(dispatch_barrier, true) -DISPATCH_INTERCEPT_SYNC_F(dispatch_async_and_wait_f, false) +// dispatch_async_and_wait() and friends were introduced in macOS 10.14. +// Linking of these interceptors fails when using an older SDK. +#if !SANITIZER_MAC || defined(__MAC_10_14) +// macOS 10.14 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 functions as "weak +// imports". Note that this file is multi-platform, so we cannot include the +// actual header file (#include ). +SANITIZER_WEAK_IMPORT void dispatch_async_and_wait( + dispatch_queue_t queue, DISPATCH_NOESCAPE dispatch_block_t block); +SANITIZER_WEAK_IMPORT void dispatch_async_and_wait_f( + dispatch_queue_t queue, void *context, dispatch_function_t work); + DISPATCH_INTERCEPT_SYNC_B(dispatch_async_and_wait, false) +DISPATCH_INTERCEPT_SYNC_F(dispatch_async_and_wait_f, false) +#endif + DECLARE_REAL(void, dispatch_after_f, dispatch_time_t when, dispatch_queue_t queue, void *context, dispatch_function_t work)