xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/tsan/rtl/tsan_interceptors_mac.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
168d75effSDimitry Andric //===-- tsan_interceptors_mac.cpp -----------------------------------------===//
268d75effSDimitry Andric //
368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
668d75effSDimitry Andric //
768d75effSDimitry Andric //===----------------------------------------------------------------------===//
868d75effSDimitry Andric //
968d75effSDimitry Andric // This file is a part of ThreadSanitizer (TSan), a race detector.
1068d75effSDimitry Andric //
1168d75effSDimitry Andric // Mac-specific interceptors.
1268d75effSDimitry Andric //===----------------------------------------------------------------------===//
1368d75effSDimitry Andric 
1468d75effSDimitry Andric #include "sanitizer_common/sanitizer_platform.h"
1581ad6265SDimitry Andric #if SANITIZER_APPLE
1668d75effSDimitry Andric 
1768d75effSDimitry Andric #include "interception/interception.h"
1868d75effSDimitry Andric #include "tsan_interceptors.h"
1968d75effSDimitry Andric #include "tsan_interface.h"
2068d75effSDimitry Andric #include "tsan_interface_ann.h"
21*06c3fb27SDimitry Andric #include "tsan_spinlock_defs_mac.h"
2268d75effSDimitry Andric #include "sanitizer_common/sanitizer_addrhashmap.h"
2368d75effSDimitry Andric 
2468d75effSDimitry Andric #include <errno.h>
2568d75effSDimitry Andric #include <libkern/OSAtomic.h>
2668d75effSDimitry Andric #include <objc/objc-sync.h>
2713138422SDimitry Andric #include <os/lock.h>
285ffd83dbSDimitry Andric #include <sys/ucontext.h>
2913138422SDimitry Andric 
3068d75effSDimitry Andric #if defined(__has_include) && __has_include(<xpc/xpc.h>)
3168d75effSDimitry Andric #include <xpc/xpc.h>
3268d75effSDimitry Andric #endif  // #if defined(__has_include) && __has_include(<xpc/xpc.h>)
3368d75effSDimitry Andric 
3468d75effSDimitry Andric typedef long long_t;
3568d75effSDimitry Andric 
3668d75effSDimitry Andric extern "C" {
3768d75effSDimitry Andric int getcontext(ucontext_t *ucp) __attribute__((returns_twice));
3868d75effSDimitry Andric int setcontext(const ucontext_t *ucp);
3968d75effSDimitry Andric }
4068d75effSDimitry Andric 
4168d75effSDimitry Andric namespace __tsan {
4268d75effSDimitry Andric 
4368d75effSDimitry Andric // The non-barrier versions of OSAtomic* functions are semantically mo_relaxed,
4468d75effSDimitry Andric // but the two variants (e.g. OSAtomicAdd32 and OSAtomicAdd32Barrier) are
4568d75effSDimitry Andric // actually aliases of each other, and we cannot have different interceptors for
4668d75effSDimitry Andric // them, because they're actually the same function.  Thus, we have to stay
4768d75effSDimitry Andric // conservative and treat the non-barrier versions as mo_acq_rel.
48fe6060f1SDimitry Andric static constexpr morder kMacOrderBarrier = mo_acq_rel;
49fe6060f1SDimitry Andric static constexpr morder kMacOrderNonBarrier = mo_acq_rel;
50fe6060f1SDimitry Andric static constexpr morder kMacFailureOrder = mo_relaxed;
5168d75effSDimitry Andric 
5268d75effSDimitry Andric #define OSATOMIC_INTERCEPTOR(return_t, t, tsan_t, f, tsan_atomic_f, mo) \
5368d75effSDimitry Andric   TSAN_INTERCEPTOR(return_t, f, t x, volatile t *ptr) {                 \
5468d75effSDimitry Andric     SCOPED_TSAN_INTERCEPTOR(f, x, ptr);                                 \
5568d75effSDimitry Andric     return tsan_atomic_f((volatile tsan_t *)ptr, x, mo);                \
5668d75effSDimitry Andric   }
5768d75effSDimitry Andric 
5868d75effSDimitry Andric #define OSATOMIC_INTERCEPTOR_PLUS_X(return_t, t, tsan_t, f, tsan_atomic_f, mo) \
5968d75effSDimitry Andric   TSAN_INTERCEPTOR(return_t, f, t x, volatile t *ptr) {                        \
6068d75effSDimitry Andric     SCOPED_TSAN_INTERCEPTOR(f, x, ptr);                                        \
6168d75effSDimitry Andric     return tsan_atomic_f((volatile tsan_t *)ptr, x, mo) + x;                   \
6268d75effSDimitry Andric   }
6368d75effSDimitry Andric 
6468d75effSDimitry Andric #define OSATOMIC_INTERCEPTOR_PLUS_1(return_t, t, tsan_t, f, tsan_atomic_f, mo) \
6568d75effSDimitry Andric   TSAN_INTERCEPTOR(return_t, f, volatile t *ptr) {                             \
6668d75effSDimitry Andric     SCOPED_TSAN_INTERCEPTOR(f, ptr);                                           \
6768d75effSDimitry Andric     return tsan_atomic_f((volatile tsan_t *)ptr, 1, mo) + 1;                   \
6868d75effSDimitry Andric   }
6968d75effSDimitry Andric 
7068d75effSDimitry Andric #define OSATOMIC_INTERCEPTOR_MINUS_1(return_t, t, tsan_t, f, tsan_atomic_f, \
7168d75effSDimitry Andric                                      mo)                                    \
7268d75effSDimitry Andric   TSAN_INTERCEPTOR(return_t, f, volatile t *ptr) {                          \
7368d75effSDimitry Andric     SCOPED_TSAN_INTERCEPTOR(f, ptr);                                        \
7468d75effSDimitry Andric     return tsan_atomic_f((volatile tsan_t *)ptr, 1, mo) - 1;                \
7568d75effSDimitry Andric   }
7668d75effSDimitry Andric 
7768d75effSDimitry Andric #define OSATOMIC_INTERCEPTORS_ARITHMETIC(f, tsan_atomic_f, m)                  \
7868d75effSDimitry Andric   m(int32_t, int32_t, a32, f##32, __tsan_atomic32_##tsan_atomic_f,             \
7968d75effSDimitry Andric     kMacOrderNonBarrier)                                                       \
8068d75effSDimitry Andric   m(int32_t, int32_t, a32, f##32##Barrier, __tsan_atomic32_##tsan_atomic_f,    \
8168d75effSDimitry Andric     kMacOrderBarrier)                                                          \
8268d75effSDimitry Andric   m(int64_t, int64_t, a64, f##64, __tsan_atomic64_##tsan_atomic_f,             \
8368d75effSDimitry Andric     kMacOrderNonBarrier)                                                       \
8468d75effSDimitry Andric   m(int64_t, int64_t, a64, f##64##Barrier, __tsan_atomic64_##tsan_atomic_f,    \
8568d75effSDimitry Andric     kMacOrderBarrier)
8668d75effSDimitry Andric 
8768d75effSDimitry Andric #define OSATOMIC_INTERCEPTORS_BITWISE(f, tsan_atomic_f, m, m_orig)             \
8868d75effSDimitry Andric   m(int32_t, uint32_t, a32, f##32, __tsan_atomic32_##tsan_atomic_f,            \
8968d75effSDimitry Andric     kMacOrderNonBarrier)                                                       \
9068d75effSDimitry Andric   m(int32_t, uint32_t, a32, f##32##Barrier, __tsan_atomic32_##tsan_atomic_f,   \
9168d75effSDimitry Andric     kMacOrderBarrier)                                                          \
9268d75effSDimitry Andric   m_orig(int32_t, uint32_t, a32, f##32##Orig, __tsan_atomic32_##tsan_atomic_f, \
9368d75effSDimitry Andric     kMacOrderNonBarrier)                                                       \
9468d75effSDimitry Andric   m_orig(int32_t, uint32_t, a32, f##32##OrigBarrier,                           \
9568d75effSDimitry Andric     __tsan_atomic32_##tsan_atomic_f, kMacOrderBarrier)
9668d75effSDimitry Andric 
OSATOMIC_INTERCEPTORS_ARITHMETIC(OSAtomicAdd,fetch_add,OSATOMIC_INTERCEPTOR_PLUS_X)9768d75effSDimitry Andric OSATOMIC_INTERCEPTORS_ARITHMETIC(OSAtomicAdd, fetch_add,
9868d75effSDimitry Andric                                  OSATOMIC_INTERCEPTOR_PLUS_X)
9968d75effSDimitry Andric OSATOMIC_INTERCEPTORS_ARITHMETIC(OSAtomicIncrement, fetch_add,
10068d75effSDimitry Andric                                  OSATOMIC_INTERCEPTOR_PLUS_1)
10168d75effSDimitry Andric OSATOMIC_INTERCEPTORS_ARITHMETIC(OSAtomicDecrement, fetch_sub,
10268d75effSDimitry Andric                                  OSATOMIC_INTERCEPTOR_MINUS_1)
10368d75effSDimitry Andric OSATOMIC_INTERCEPTORS_BITWISE(OSAtomicOr, fetch_or, OSATOMIC_INTERCEPTOR_PLUS_X,
10468d75effSDimitry Andric                               OSATOMIC_INTERCEPTOR)
10568d75effSDimitry Andric OSATOMIC_INTERCEPTORS_BITWISE(OSAtomicAnd, fetch_and,
10668d75effSDimitry Andric                               OSATOMIC_INTERCEPTOR_PLUS_X, OSATOMIC_INTERCEPTOR)
10768d75effSDimitry Andric OSATOMIC_INTERCEPTORS_BITWISE(OSAtomicXor, fetch_xor,
10868d75effSDimitry Andric                               OSATOMIC_INTERCEPTOR_PLUS_X, OSATOMIC_INTERCEPTOR)
10968d75effSDimitry Andric 
11068d75effSDimitry Andric #define OSATOMIC_INTERCEPTORS_CAS(f, tsan_atomic_f, tsan_t, t)              \
11168d75effSDimitry Andric   TSAN_INTERCEPTOR(bool, f, t old_value, t new_value, t volatile *ptr) {    \
11268d75effSDimitry Andric     SCOPED_TSAN_INTERCEPTOR(f, old_value, new_value, ptr);                  \
11368d75effSDimitry Andric     return tsan_atomic_f##_compare_exchange_strong(                         \
11468d75effSDimitry Andric         (volatile tsan_t *)ptr, (tsan_t *)&old_value, (tsan_t)new_value,    \
115fe6060f1SDimitry Andric         kMacOrderNonBarrier, kMacFailureOrder);                             \
11668d75effSDimitry Andric   }                                                                         \
11768d75effSDimitry Andric                                                                             \
11868d75effSDimitry Andric   TSAN_INTERCEPTOR(bool, f##Barrier, t old_value, t new_value,              \
11968d75effSDimitry Andric                    t volatile *ptr) {                                       \
12068d75effSDimitry Andric     SCOPED_TSAN_INTERCEPTOR(f##Barrier, old_value, new_value, ptr);         \
12168d75effSDimitry Andric     return tsan_atomic_f##_compare_exchange_strong(                         \
12268d75effSDimitry Andric         (volatile tsan_t *)ptr, (tsan_t *)&old_value, (tsan_t)new_value,    \
123fe6060f1SDimitry Andric         kMacOrderBarrier, kMacFailureOrder);                                \
12468d75effSDimitry Andric   }
12568d75effSDimitry Andric 
12668d75effSDimitry Andric OSATOMIC_INTERCEPTORS_CAS(OSAtomicCompareAndSwapInt, __tsan_atomic32, a32, int)
12768d75effSDimitry Andric OSATOMIC_INTERCEPTORS_CAS(OSAtomicCompareAndSwapLong, __tsan_atomic64, a64,
12868d75effSDimitry Andric                           long_t)
12968d75effSDimitry Andric OSATOMIC_INTERCEPTORS_CAS(OSAtomicCompareAndSwapPtr, __tsan_atomic64, a64,
13068d75effSDimitry Andric                           void *)
13168d75effSDimitry Andric OSATOMIC_INTERCEPTORS_CAS(OSAtomicCompareAndSwap32, __tsan_atomic32, a32,
13268d75effSDimitry Andric                           int32_t)
13368d75effSDimitry Andric OSATOMIC_INTERCEPTORS_CAS(OSAtomicCompareAndSwap64, __tsan_atomic64, a64,
13468d75effSDimitry Andric                           int64_t)
13568d75effSDimitry Andric 
13668d75effSDimitry Andric #define OSATOMIC_INTERCEPTOR_BITOP(f, op, clear, mo)             \
13768d75effSDimitry Andric   TSAN_INTERCEPTOR(bool, f, uint32_t n, volatile void *ptr) {    \
13868d75effSDimitry Andric     SCOPED_TSAN_INTERCEPTOR(f, n, ptr);                          \
13968d75effSDimitry Andric     volatile char *byte_ptr = ((volatile char *)ptr) + (n >> 3); \
14068d75effSDimitry Andric     char bit = 0x80u >> (n & 7);                                 \
14168d75effSDimitry Andric     char mask = clear ? ~bit : bit;                              \
14268d75effSDimitry Andric     char orig_byte = op((volatile a8 *)byte_ptr, mask, mo);      \
14368d75effSDimitry Andric     return orig_byte & bit;                                      \
14468d75effSDimitry Andric   }
14568d75effSDimitry Andric 
14668d75effSDimitry Andric #define OSATOMIC_INTERCEPTORS_BITOP(f, op, clear)               \
14768d75effSDimitry Andric   OSATOMIC_INTERCEPTOR_BITOP(f, op, clear, kMacOrderNonBarrier) \
14868d75effSDimitry Andric   OSATOMIC_INTERCEPTOR_BITOP(f##Barrier, op, clear, kMacOrderBarrier)
14968d75effSDimitry Andric 
15068d75effSDimitry Andric OSATOMIC_INTERCEPTORS_BITOP(OSAtomicTestAndSet, __tsan_atomic8_fetch_or, false)
15168d75effSDimitry Andric OSATOMIC_INTERCEPTORS_BITOP(OSAtomicTestAndClear, __tsan_atomic8_fetch_and,
15268d75effSDimitry Andric                             true)
15368d75effSDimitry Andric 
15468d75effSDimitry Andric TSAN_INTERCEPTOR(void, OSAtomicEnqueue, OSQueueHead *list, void *item,
15568d75effSDimitry Andric                  size_t offset) {
15668d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(OSAtomicEnqueue, list, item, offset);
15768d75effSDimitry Andric   __tsan_release(item);
15868d75effSDimitry Andric   REAL(OSAtomicEnqueue)(list, item, offset);
15968d75effSDimitry Andric }
16068d75effSDimitry Andric 
TSAN_INTERCEPTOR(void *,OSAtomicDequeue,OSQueueHead * list,size_t offset)16168d75effSDimitry Andric TSAN_INTERCEPTOR(void *, OSAtomicDequeue, OSQueueHead *list, size_t offset) {
16268d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(OSAtomicDequeue, list, offset);
16368d75effSDimitry Andric   void *item = REAL(OSAtomicDequeue)(list, offset);
16468d75effSDimitry Andric   if (item) __tsan_acquire(item);
16568d75effSDimitry Andric   return item;
16668d75effSDimitry Andric }
16768d75effSDimitry Andric 
16868d75effSDimitry Andric // OSAtomicFifoEnqueue and OSAtomicFifoDequeue are only on OS X.
16968d75effSDimitry Andric #if !SANITIZER_IOS
17068d75effSDimitry Andric 
TSAN_INTERCEPTOR(void,OSAtomicFifoEnqueue,OSFifoQueueHead * list,void * item,size_t offset)17168d75effSDimitry Andric TSAN_INTERCEPTOR(void, OSAtomicFifoEnqueue, OSFifoQueueHead *list, void *item,
17268d75effSDimitry Andric                  size_t offset) {
17368d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(OSAtomicFifoEnqueue, list, item, offset);
17468d75effSDimitry Andric   __tsan_release(item);
17568d75effSDimitry Andric   REAL(OSAtomicFifoEnqueue)(list, item, offset);
17668d75effSDimitry Andric }
17768d75effSDimitry Andric 
TSAN_INTERCEPTOR(void *,OSAtomicFifoDequeue,OSFifoQueueHead * list,size_t offset)17868d75effSDimitry Andric TSAN_INTERCEPTOR(void *, OSAtomicFifoDequeue, OSFifoQueueHead *list,
17968d75effSDimitry Andric                  size_t offset) {
18068d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(OSAtomicFifoDequeue, list, offset);
18168d75effSDimitry Andric   void *item = REAL(OSAtomicFifoDequeue)(list, offset);
18268d75effSDimitry Andric   if (item) __tsan_acquire(item);
18368d75effSDimitry Andric   return item;
18468d75effSDimitry Andric }
18568d75effSDimitry Andric 
18668d75effSDimitry Andric #endif
18768d75effSDimitry Andric 
TSAN_INTERCEPTOR(void,OSSpinLockLock,volatile OSSpinLock * lock)18868d75effSDimitry Andric TSAN_INTERCEPTOR(void, OSSpinLockLock, volatile OSSpinLock *lock) {
18968d75effSDimitry Andric   CHECK(!cur_thread()->is_dead);
19068d75effSDimitry Andric   if (!cur_thread()->is_inited) {
19168d75effSDimitry Andric     return REAL(OSSpinLockLock)(lock);
19268d75effSDimitry Andric   }
19368d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(OSSpinLockLock, lock);
19468d75effSDimitry Andric   REAL(OSSpinLockLock)(lock);
19568d75effSDimitry Andric   Acquire(thr, pc, (uptr)lock);
19668d75effSDimitry Andric }
19768d75effSDimitry Andric 
TSAN_INTERCEPTOR(bool,OSSpinLockTry,volatile OSSpinLock * lock)19868d75effSDimitry Andric TSAN_INTERCEPTOR(bool, OSSpinLockTry, volatile OSSpinLock *lock) {
19968d75effSDimitry Andric   CHECK(!cur_thread()->is_dead);
20068d75effSDimitry Andric   if (!cur_thread()->is_inited) {
20168d75effSDimitry Andric     return REAL(OSSpinLockTry)(lock);
20268d75effSDimitry Andric   }
20368d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(OSSpinLockTry, lock);
20468d75effSDimitry Andric   bool result = REAL(OSSpinLockTry)(lock);
20568d75effSDimitry Andric   if (result)
20668d75effSDimitry Andric     Acquire(thr, pc, (uptr)lock);
20768d75effSDimitry Andric   return result;
20868d75effSDimitry Andric }
20968d75effSDimitry Andric 
TSAN_INTERCEPTOR(void,OSSpinLockUnlock,volatile OSSpinLock * lock)21068d75effSDimitry Andric TSAN_INTERCEPTOR(void, OSSpinLockUnlock, volatile OSSpinLock *lock) {
21168d75effSDimitry Andric   CHECK(!cur_thread()->is_dead);
21268d75effSDimitry Andric   if (!cur_thread()->is_inited) {
21368d75effSDimitry Andric     return REAL(OSSpinLockUnlock)(lock);
21468d75effSDimitry Andric   }
21568d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(OSSpinLockUnlock, lock);
21668d75effSDimitry Andric   Release(thr, pc, (uptr)lock);
21768d75effSDimitry Andric   REAL(OSSpinLockUnlock)(lock);
21868d75effSDimitry Andric }
21968d75effSDimitry Andric 
TSAN_INTERCEPTOR(void,os_lock_lock,void * lock)22068d75effSDimitry Andric TSAN_INTERCEPTOR(void, os_lock_lock, void *lock) {
22168d75effSDimitry Andric   CHECK(!cur_thread()->is_dead);
22268d75effSDimitry Andric   if (!cur_thread()->is_inited) {
22368d75effSDimitry Andric     return REAL(os_lock_lock)(lock);
22468d75effSDimitry Andric   }
22568d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(os_lock_lock, lock);
22668d75effSDimitry Andric   REAL(os_lock_lock)(lock);
22768d75effSDimitry Andric   Acquire(thr, pc, (uptr)lock);
22868d75effSDimitry Andric }
22968d75effSDimitry Andric 
TSAN_INTERCEPTOR(bool,os_lock_trylock,void * lock)23068d75effSDimitry Andric TSAN_INTERCEPTOR(bool, os_lock_trylock, void *lock) {
23168d75effSDimitry Andric   CHECK(!cur_thread()->is_dead);
23268d75effSDimitry Andric   if (!cur_thread()->is_inited) {
23368d75effSDimitry Andric     return REAL(os_lock_trylock)(lock);
23468d75effSDimitry Andric   }
23568d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(os_lock_trylock, lock);
23668d75effSDimitry Andric   bool result = REAL(os_lock_trylock)(lock);
23768d75effSDimitry Andric   if (result)
23868d75effSDimitry Andric     Acquire(thr, pc, (uptr)lock);
23968d75effSDimitry Andric   return result;
24068d75effSDimitry Andric }
24168d75effSDimitry Andric 
TSAN_INTERCEPTOR(void,os_lock_unlock,void * lock)24268d75effSDimitry Andric TSAN_INTERCEPTOR(void, os_lock_unlock, void *lock) {
24368d75effSDimitry Andric   CHECK(!cur_thread()->is_dead);
24468d75effSDimitry Andric   if (!cur_thread()->is_inited) {
24568d75effSDimitry Andric     return REAL(os_lock_unlock)(lock);
24668d75effSDimitry Andric   }
24768d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(os_lock_unlock, lock);
24868d75effSDimitry Andric   Release(thr, pc, (uptr)lock);
24968d75effSDimitry Andric   REAL(os_lock_unlock)(lock);
25068d75effSDimitry Andric }
25168d75effSDimitry Andric 
TSAN_INTERCEPTOR(void,os_unfair_lock_lock,os_unfair_lock_t lock)25268d75effSDimitry Andric TSAN_INTERCEPTOR(void, os_unfair_lock_lock, os_unfair_lock_t lock) {
25368d75effSDimitry Andric   if (!cur_thread()->is_inited || cur_thread()->is_dead) {
25468d75effSDimitry Andric     return REAL(os_unfair_lock_lock)(lock);
25568d75effSDimitry Andric   }
25668d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(os_unfair_lock_lock, lock);
25768d75effSDimitry Andric   REAL(os_unfair_lock_lock)(lock);
25868d75effSDimitry Andric   Acquire(thr, pc, (uptr)lock);
25968d75effSDimitry Andric }
26068d75effSDimitry Andric 
TSAN_INTERCEPTOR(void,os_unfair_lock_lock_with_options,os_unfair_lock_t lock,u32 options)26168d75effSDimitry Andric TSAN_INTERCEPTOR(void, os_unfair_lock_lock_with_options, os_unfair_lock_t lock,
26268d75effSDimitry Andric                  u32 options) {
26368d75effSDimitry Andric   if (!cur_thread()->is_inited || cur_thread()->is_dead) {
26468d75effSDimitry Andric     return REAL(os_unfair_lock_lock_with_options)(lock, options);
26568d75effSDimitry Andric   }
26668d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(os_unfair_lock_lock_with_options, lock, options);
26768d75effSDimitry Andric   REAL(os_unfair_lock_lock_with_options)(lock, options);
26868d75effSDimitry Andric   Acquire(thr, pc, (uptr)lock);
26968d75effSDimitry Andric }
27068d75effSDimitry Andric 
TSAN_INTERCEPTOR(bool,os_unfair_lock_trylock,os_unfair_lock_t lock)27168d75effSDimitry Andric TSAN_INTERCEPTOR(bool, os_unfair_lock_trylock, os_unfair_lock_t lock) {
27268d75effSDimitry Andric   if (!cur_thread()->is_inited || cur_thread()->is_dead) {
27368d75effSDimitry Andric     return REAL(os_unfair_lock_trylock)(lock);
27468d75effSDimitry Andric   }
27568d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(os_unfair_lock_trylock, lock);
27668d75effSDimitry Andric   bool result = REAL(os_unfair_lock_trylock)(lock);
27768d75effSDimitry Andric   if (result)
27868d75effSDimitry Andric     Acquire(thr, pc, (uptr)lock);
27968d75effSDimitry Andric   return result;
28068d75effSDimitry Andric }
28168d75effSDimitry Andric 
TSAN_INTERCEPTOR(void,os_unfair_lock_unlock,os_unfair_lock_t lock)28268d75effSDimitry Andric TSAN_INTERCEPTOR(void, os_unfair_lock_unlock, os_unfair_lock_t lock) {
28368d75effSDimitry Andric   if (!cur_thread()->is_inited || cur_thread()->is_dead) {
28468d75effSDimitry Andric     return REAL(os_unfair_lock_unlock)(lock);
28568d75effSDimitry Andric   }
28668d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(os_unfair_lock_unlock, lock);
28768d75effSDimitry Andric   Release(thr, pc, (uptr)lock);
28868d75effSDimitry Andric   REAL(os_unfair_lock_unlock)(lock);
28968d75effSDimitry Andric }
29068d75effSDimitry Andric 
29168d75effSDimitry Andric #if defined(__has_include) && __has_include(<xpc/xpc.h>)
29268d75effSDimitry Andric 
TSAN_INTERCEPTOR(void,xpc_connection_set_event_handler,xpc_connection_t connection,xpc_handler_t handler)29368d75effSDimitry Andric TSAN_INTERCEPTOR(void, xpc_connection_set_event_handler,
29468d75effSDimitry Andric                  xpc_connection_t connection, xpc_handler_t handler) {
29568d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(xpc_connection_set_event_handler, connection,
29668d75effSDimitry Andric                           handler);
29768d75effSDimitry Andric   Release(thr, pc, (uptr)connection);
29868d75effSDimitry Andric   xpc_handler_t new_handler = ^(xpc_object_t object) {
29968d75effSDimitry Andric     {
30068d75effSDimitry Andric       SCOPED_INTERCEPTOR_RAW(xpc_connection_set_event_handler);
30168d75effSDimitry Andric       Acquire(thr, pc, (uptr)connection);
30268d75effSDimitry Andric     }
30368d75effSDimitry Andric     handler(object);
30468d75effSDimitry Andric   };
30568d75effSDimitry Andric   REAL(xpc_connection_set_event_handler)(connection, new_handler);
30668d75effSDimitry Andric }
30768d75effSDimitry Andric 
TSAN_INTERCEPTOR(void,xpc_connection_send_barrier,xpc_connection_t connection,dispatch_block_t barrier)30868d75effSDimitry Andric TSAN_INTERCEPTOR(void, xpc_connection_send_barrier, xpc_connection_t connection,
30968d75effSDimitry Andric                  dispatch_block_t barrier) {
31068d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(xpc_connection_send_barrier, connection, barrier);
31168d75effSDimitry Andric   Release(thr, pc, (uptr)connection);
31268d75effSDimitry Andric   dispatch_block_t new_barrier = ^() {
31368d75effSDimitry Andric     {
31468d75effSDimitry Andric       SCOPED_INTERCEPTOR_RAW(xpc_connection_send_barrier);
31568d75effSDimitry Andric       Acquire(thr, pc, (uptr)connection);
31668d75effSDimitry Andric     }
31768d75effSDimitry Andric     barrier();
31868d75effSDimitry Andric   };
31968d75effSDimitry Andric   REAL(xpc_connection_send_barrier)(connection, new_barrier);
32068d75effSDimitry Andric }
32168d75effSDimitry Andric 
TSAN_INTERCEPTOR(void,xpc_connection_send_message_with_reply,xpc_connection_t connection,xpc_object_t message,dispatch_queue_t replyq,xpc_handler_t handler)32268d75effSDimitry Andric TSAN_INTERCEPTOR(void, xpc_connection_send_message_with_reply,
32368d75effSDimitry Andric                  xpc_connection_t connection, xpc_object_t message,
32468d75effSDimitry Andric                  dispatch_queue_t replyq, xpc_handler_t handler) {
32568d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(xpc_connection_send_message_with_reply, connection,
32668d75effSDimitry Andric                           message, replyq, handler);
32768d75effSDimitry Andric   Release(thr, pc, (uptr)connection);
32868d75effSDimitry Andric   xpc_handler_t new_handler = ^(xpc_object_t object) {
32968d75effSDimitry Andric     {
33068d75effSDimitry Andric       SCOPED_INTERCEPTOR_RAW(xpc_connection_send_message_with_reply);
33168d75effSDimitry Andric       Acquire(thr, pc, (uptr)connection);
33268d75effSDimitry Andric     }
33368d75effSDimitry Andric     handler(object);
33468d75effSDimitry Andric   };
33568d75effSDimitry Andric   REAL(xpc_connection_send_message_with_reply)
33668d75effSDimitry Andric   (connection, message, replyq, new_handler);
33768d75effSDimitry Andric }
33868d75effSDimitry Andric 
TSAN_INTERCEPTOR(void,xpc_connection_cancel,xpc_connection_t connection)33968d75effSDimitry Andric TSAN_INTERCEPTOR(void, xpc_connection_cancel, xpc_connection_t connection) {
34068d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(xpc_connection_cancel, connection);
34168d75effSDimitry Andric   Release(thr, pc, (uptr)connection);
34268d75effSDimitry Andric   REAL(xpc_connection_cancel)(connection);
34368d75effSDimitry Andric }
34468d75effSDimitry Andric 
34568d75effSDimitry Andric #endif  // #if defined(__has_include) && __has_include(<xpc/xpc.h>)
34668d75effSDimitry Andric 
34768d75effSDimitry Andric // Determines whether the Obj-C object pointer is a tagged pointer. Tagged
34868d75effSDimitry Andric // pointers encode the object data directly in their pointer bits and do not
34968d75effSDimitry Andric // have an associated memory allocation. The Obj-C runtime uses tagged pointers
35068d75effSDimitry Andric // to transparently optimize small objects.
IsTaggedObjCPointer(id obj)35168d75effSDimitry Andric static bool IsTaggedObjCPointer(id obj) {
35268d75effSDimitry Andric   const uptr kPossibleTaggedBits = 0x8000000000000001ull;
35368d75effSDimitry Andric   return ((uptr)obj & kPossibleTaggedBits) != 0;
35468d75effSDimitry Andric }
35568d75effSDimitry Andric 
35668d75effSDimitry Andric // Returns an address which can be used to inform TSan about synchronization
35768d75effSDimitry Andric // points (MutexLock/Unlock). The TSan infrastructure expects this to be a valid
35868d75effSDimitry Andric // address in the process space. We do a small allocation here to obtain a
35968d75effSDimitry Andric // stable address (the array backing the hash map can change). The memory is
36068d75effSDimitry Andric // never free'd (leaked) and allocation and locking are slow, but this code only
36168d75effSDimitry Andric // runs for @synchronized with tagged pointers, which is very rare.
GetOrCreateSyncAddress(uptr addr,ThreadState * thr,uptr pc)36268d75effSDimitry Andric static uptr GetOrCreateSyncAddress(uptr addr, ThreadState *thr, uptr pc) {
36368d75effSDimitry Andric   typedef AddrHashMap<uptr, 5> Map;
36468d75effSDimitry Andric   static Map Addresses;
36568d75effSDimitry Andric   Map::Handle h(&Addresses, addr);
36668d75effSDimitry Andric   if (h.created()) {
36768d75effSDimitry Andric     ThreadIgnoreBegin(thr, pc);
36868d75effSDimitry Andric     *h = (uptr) user_alloc(thr, pc, /*size=*/1);
369349cc55cSDimitry Andric     ThreadIgnoreEnd(thr);
37068d75effSDimitry Andric   }
37168d75effSDimitry Andric   return *h;
37268d75effSDimitry Andric }
37368d75effSDimitry Andric 
37468d75effSDimitry Andric // Returns an address on which we can synchronize given an Obj-C object pointer.
37568d75effSDimitry Andric // For normal object pointers, this is just the address of the object in memory.
37668d75effSDimitry Andric // Tagged pointers are not backed by an actual memory allocation, so we need to
37768d75effSDimitry Andric // synthesize a valid address.
SyncAddressForObjCObject(id obj,ThreadState * thr,uptr pc)37868d75effSDimitry Andric static uptr SyncAddressForObjCObject(id obj, ThreadState *thr, uptr pc) {
37968d75effSDimitry Andric   if (IsTaggedObjCPointer(obj))
38068d75effSDimitry Andric     return GetOrCreateSyncAddress((uptr)obj, thr, pc);
38168d75effSDimitry Andric   return (uptr)obj;
38268d75effSDimitry Andric }
38368d75effSDimitry Andric 
TSAN_INTERCEPTOR(int,objc_sync_enter,id obj)38468d75effSDimitry Andric TSAN_INTERCEPTOR(int, objc_sync_enter, id obj) {
38568d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(objc_sync_enter, obj);
38668d75effSDimitry Andric   if (!obj) return REAL(objc_sync_enter)(obj);
38768d75effSDimitry Andric   uptr addr = SyncAddressForObjCObject(obj, thr, pc);
38868d75effSDimitry Andric   MutexPreLock(thr, pc, addr, MutexFlagWriteReentrant);
38968d75effSDimitry Andric   int result = REAL(objc_sync_enter)(obj);
39068d75effSDimitry Andric   CHECK_EQ(result, OBJC_SYNC_SUCCESS);
39168d75effSDimitry Andric   MutexPostLock(thr, pc, addr, MutexFlagWriteReentrant);
39268d75effSDimitry Andric   return result;
39368d75effSDimitry Andric }
39468d75effSDimitry Andric 
TSAN_INTERCEPTOR(int,objc_sync_exit,id obj)39568d75effSDimitry Andric TSAN_INTERCEPTOR(int, objc_sync_exit, id obj) {
39668d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(objc_sync_exit, obj);
39768d75effSDimitry Andric   if (!obj) return REAL(objc_sync_exit)(obj);
39868d75effSDimitry Andric   uptr addr = SyncAddressForObjCObject(obj, thr, pc);
39968d75effSDimitry Andric   MutexUnlock(thr, pc, addr);
40068d75effSDimitry Andric   int result = REAL(objc_sync_exit)(obj);
40168d75effSDimitry Andric   if (result != OBJC_SYNC_SUCCESS) MutexInvalidAccess(thr, pc, addr);
40268d75effSDimitry Andric   return result;
40368d75effSDimitry Andric }
40468d75effSDimitry Andric 
TSAN_INTERCEPTOR(int,swapcontext,ucontext_t * oucp,const ucontext_t * ucp)40568d75effSDimitry Andric TSAN_INTERCEPTOR(int, swapcontext, ucontext_t *oucp, const ucontext_t *ucp) {
40668d75effSDimitry Andric   {
40768d75effSDimitry Andric     SCOPED_INTERCEPTOR_RAW(swapcontext, oucp, ucp);
40868d75effSDimitry Andric   }
409349cc55cSDimitry Andric   // Because of swapcontext() semantics we have no option but to copy its
410349cc55cSDimitry Andric   // implementation here
41168d75effSDimitry Andric   if (!oucp || !ucp) {
41268d75effSDimitry Andric     errno = EINVAL;
41368d75effSDimitry Andric     return -1;
41468d75effSDimitry Andric   }
41568d75effSDimitry Andric   ThreadState *thr = cur_thread();
41668d75effSDimitry Andric   const int UCF_SWAPPED = 0x80000000;
41768d75effSDimitry Andric   oucp->uc_onstack &= ~UCF_SWAPPED;
41868d75effSDimitry Andric   thr->ignore_interceptors++;
41968d75effSDimitry Andric   int ret = getcontext(oucp);
42068d75effSDimitry Andric   if (!(oucp->uc_onstack & UCF_SWAPPED)) {
42168d75effSDimitry Andric     thr->ignore_interceptors--;
42268d75effSDimitry Andric     if (!ret) {
42368d75effSDimitry Andric       oucp->uc_onstack |= UCF_SWAPPED;
42468d75effSDimitry Andric       ret = setcontext(ucp);
42568d75effSDimitry Andric     }
42668d75effSDimitry Andric   }
42768d75effSDimitry Andric   return ret;
42868d75effSDimitry Andric }
42968d75effSDimitry Andric 
43068d75effSDimitry Andric // On macOS, libc++ is always linked dynamically, so intercepting works the
43168d75effSDimitry Andric // usual way.
43268d75effSDimitry Andric #define STDCXX_INTERCEPTOR TSAN_INTERCEPTOR
43368d75effSDimitry Andric 
43468d75effSDimitry Andric namespace {
43568d75effSDimitry Andric struct fake_shared_weak_count {
43668d75effSDimitry Andric   volatile a64 shared_owners;
43768d75effSDimitry Andric   volatile a64 shared_weak_owners;
43868d75effSDimitry Andric   virtual void _unused_0x0() = 0;
43968d75effSDimitry Andric   virtual void _unused_0x8() = 0;
44068d75effSDimitry Andric   virtual void on_zero_shared() = 0;
44168d75effSDimitry Andric   virtual void _unused_0x18() = 0;
44268d75effSDimitry Andric   virtual void on_zero_shared_weak() = 0;
443e8d8bef9SDimitry Andric   virtual ~fake_shared_weak_count() = 0;  // suppress -Wnon-virtual-dtor
44468d75effSDimitry Andric };
44568d75effSDimitry Andric }  // namespace
44668d75effSDimitry Andric 
44768d75effSDimitry Andric // The following code adds libc++ interceptors for:
44868d75effSDimitry Andric //     void __shared_weak_count::__release_shared() _NOEXCEPT;
44968d75effSDimitry Andric //     bool __shared_count::__release_shared() _NOEXCEPT;
45068d75effSDimitry Andric // Shared and weak pointers in C++ maintain reference counts via atomics in
45168d75effSDimitry Andric // libc++.dylib, which are TSan-invisible, and this leads to false positives in
45268d75effSDimitry Andric // destructor code. These interceptors re-implements the whole functions so that
45368d75effSDimitry Andric // the mo_acq_rel semantics of the atomic decrement are visible.
45468d75effSDimitry Andric //
45568d75effSDimitry Andric // Unfortunately, the interceptors cannot simply Acquire/Release some sync
45668d75effSDimitry Andric // object and call the original function, because it would have a race between
45768d75effSDimitry Andric // the sync and the destruction of the object.  Calling both under a lock will
45868d75effSDimitry Andric // not work because the destructor can invoke this interceptor again (and even
45968d75effSDimitry Andric // in a different thread, so recursive locks don't help).
46068d75effSDimitry Andric 
STDCXX_INTERCEPTOR(void,_ZNSt3__119__shared_weak_count16__release_sharedEv,fake_shared_weak_count * o)46168d75effSDimitry Andric STDCXX_INTERCEPTOR(void, _ZNSt3__119__shared_weak_count16__release_sharedEv,
46268d75effSDimitry Andric                    fake_shared_weak_count *o) {
46368d75effSDimitry Andric   if (!flags()->shared_ptr_interceptor)
46468d75effSDimitry Andric     return REAL(_ZNSt3__119__shared_weak_count16__release_sharedEv)(o);
46568d75effSDimitry Andric 
46668d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(_ZNSt3__119__shared_weak_count16__release_sharedEv,
46768d75effSDimitry Andric                           o);
46868d75effSDimitry Andric   if (__tsan_atomic64_fetch_add(&o->shared_owners, -1, mo_release) == 0) {
46968d75effSDimitry Andric     Acquire(thr, pc, (uptr)&o->shared_owners);
47068d75effSDimitry Andric     o->on_zero_shared();
47168d75effSDimitry Andric     if (__tsan_atomic64_fetch_add(&o->shared_weak_owners, -1, mo_release) ==
47268d75effSDimitry Andric         0) {
47368d75effSDimitry Andric       Acquire(thr, pc, (uptr)&o->shared_weak_owners);
47468d75effSDimitry Andric       o->on_zero_shared_weak();
47568d75effSDimitry Andric     }
47668d75effSDimitry Andric   }
47768d75effSDimitry Andric }
47868d75effSDimitry Andric 
STDCXX_INTERCEPTOR(bool,_ZNSt3__114__shared_count16__release_sharedEv,fake_shared_weak_count * o)47968d75effSDimitry Andric STDCXX_INTERCEPTOR(bool, _ZNSt3__114__shared_count16__release_sharedEv,
48068d75effSDimitry Andric                    fake_shared_weak_count *o) {
48168d75effSDimitry Andric   if (!flags()->shared_ptr_interceptor)
48268d75effSDimitry Andric     return REAL(_ZNSt3__114__shared_count16__release_sharedEv)(o);
48368d75effSDimitry Andric 
48468d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(_ZNSt3__114__shared_count16__release_sharedEv, o);
48568d75effSDimitry Andric   if (__tsan_atomic64_fetch_add(&o->shared_owners, -1, mo_release) == 0) {
48668d75effSDimitry Andric     Acquire(thr, pc, (uptr)&o->shared_owners);
48768d75effSDimitry Andric     o->on_zero_shared();
48868d75effSDimitry Andric     return true;
48968d75effSDimitry Andric   }
49068d75effSDimitry Andric   return false;
49168d75effSDimitry Andric }
49268d75effSDimitry Andric 
49368d75effSDimitry Andric namespace {
49468d75effSDimitry Andric struct call_once_callback_args {
49568d75effSDimitry Andric   void (*orig_func)(void *arg);
49668d75effSDimitry Andric   void *orig_arg;
49768d75effSDimitry Andric   void *flag;
49868d75effSDimitry Andric };
49968d75effSDimitry Andric 
call_once_callback_wrapper(void * arg)50068d75effSDimitry Andric void call_once_callback_wrapper(void *arg) {
50168d75effSDimitry Andric   call_once_callback_args *new_args = (call_once_callback_args *)arg;
50268d75effSDimitry Andric   new_args->orig_func(new_args->orig_arg);
50368d75effSDimitry Andric   __tsan_release(new_args->flag);
50468d75effSDimitry Andric }
50568d75effSDimitry Andric }  // namespace
50668d75effSDimitry Andric 
50768d75effSDimitry Andric // This adds a libc++ interceptor for:
50868d75effSDimitry Andric //     void __call_once(volatile unsigned long&, void*, void(*)(void*));
50968d75effSDimitry Andric // C++11 call_once is implemented via an internal function __call_once which is
51068d75effSDimitry Andric // inside libc++.dylib, and the atomic release store inside it is thus
51168d75effSDimitry Andric // TSan-invisible. To avoid false positives, this interceptor wraps the callback
51268d75effSDimitry Andric // function and performs an explicit Release after the user code has run.
STDCXX_INTERCEPTOR(void,_ZNSt3__111__call_onceERVmPvPFvS2_E,void * flag,void * arg,void (* func)(void * arg))51368d75effSDimitry Andric STDCXX_INTERCEPTOR(void, _ZNSt3__111__call_onceERVmPvPFvS2_E, void *flag,
51468d75effSDimitry Andric                    void *arg, void (*func)(void *arg)) {
51568d75effSDimitry Andric   call_once_callback_args new_args = {func, arg, flag};
51668d75effSDimitry Andric   REAL(_ZNSt3__111__call_onceERVmPvPFvS2_E)(flag, &new_args,
51768d75effSDimitry Andric                                             call_once_callback_wrapper);
51868d75effSDimitry Andric }
51968d75effSDimitry Andric 
52068d75effSDimitry Andric }  // namespace __tsan
52168d75effSDimitry Andric 
52281ad6265SDimitry Andric #endif  // SANITIZER_APPLE
523