[TSan][libdispatch] Ensure TSan dylib works on old systems

`dispatch_async_and_wait()` was introduced in macOS 10.14, which is
greater than our minimal deployment target.  We need to forward declare
it as a "weak import" to ensure we generate a weak reference so the TSan
dylib continues to work on older systems.  We cannot simply `#include
<dispatch.h>` or use the Darwin availability macros since this file is
multi-platform.

In addition, we want to prevent building these interceptors at all when
building with older SDKs because linking always fails.

Before:
```
➤ dyldinfo -bind ./lib/clang/12.0.0/lib/darwin/libclang_rt.tsan_osx_dynamic.dylib | grep dispatch_async_and_wait
__DATA  __interpose      0x000F5E68    pointer      0 libSystem        _dispatch_async_and_wait_f
```

After:
```
➤ dyldinfo -bind ./lib/clang/12.0.0/lib/darwin/libclang_rt.tsan_osx_dynamic.dylib | grep dispatch_async_and_wait
__DATA  __got            0x000EC0A8    pointer      0 libSystem        _dispatch_async_and_wait (weak import)
__DATA  __interpose      0x000F5E78    pointer      0 libSystem        _dispatch_async_and_wait (weak import)
```

This is a follow-up to D85854 and should fix:
https://reviews.llvm.org/D85854#2221529

Reviewed By: kubamracek

Differential Revision: https://reviews.llvm.org/D86103
This commit is contained in:
Julian Lettner 2020-08-17 12:41:18 -07:00
parent 0c4863a253
commit 686fe293e6
2 changed files with 29 additions and 3 deletions

View File

@ -51,11 +51,18 @@ extern const dispatch_block_t _dispatch_data_destructor_munmap;
#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;

View File

@ -19,6 +19,10 @@
#include "BlocksRuntime/Block.h"
#include "tsan_dispatch_defs.h"
#if SANITIZER_MAC
# include <Availability.h>
#endif
namespace __tsan {
typedef u16 uint16_t;
@ -219,8 +223,23 @@ static void invoke_and_release_block(void *param) {
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 <dispatch/dispatch.h>).
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)