xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
168d75effSDimitry Andric //===-- tsan_interceptors_posix.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 // FIXME: move as many interceptors as possible into
1268d75effSDimitry Andric // sanitizer_common/sanitizer_common_interceptors.inc
1368d75effSDimitry Andric //===----------------------------------------------------------------------===//
1468d75effSDimitry Andric 
1568d75effSDimitry Andric #include "sanitizer_common/sanitizer_atomic.h"
1668d75effSDimitry Andric #include "sanitizer_common/sanitizer_errno.h"
17439352acSDimitry Andric #include "sanitizer_common/sanitizer_glibc_version.h"
1868d75effSDimitry Andric #include "sanitizer_common/sanitizer_libc.h"
1968d75effSDimitry Andric #include "sanitizer_common/sanitizer_linux.h"
2068d75effSDimitry Andric #include "sanitizer_common/sanitizer_platform_limits_netbsd.h"
2168d75effSDimitry Andric #include "sanitizer_common/sanitizer_platform_limits_posix.h"
2268d75effSDimitry Andric #include "sanitizer_common/sanitizer_placement_new.h"
2368d75effSDimitry Andric #include "sanitizer_common/sanitizer_posix.h"
2468d75effSDimitry Andric #include "sanitizer_common/sanitizer_stacktrace.h"
2568d75effSDimitry Andric #include "sanitizer_common/sanitizer_tls_get_addr.h"
2668d75effSDimitry Andric #include "interception/interception.h"
2768d75effSDimitry Andric #include "tsan_interceptors.h"
2868d75effSDimitry Andric #include "tsan_interface.h"
2968d75effSDimitry Andric #include "tsan_platform.h"
3068d75effSDimitry Andric #include "tsan_suppressions.h"
3168d75effSDimitry Andric #include "tsan_rtl.h"
3268d75effSDimitry Andric #include "tsan_mman.h"
3368d75effSDimitry Andric #include "tsan_fd.h"
3468d75effSDimitry Andric 
35e8d8bef9SDimitry Andric #include <stdarg.h>
36e8d8bef9SDimitry Andric 
3768d75effSDimitry Andric using namespace __tsan;
3868d75effSDimitry Andric 
3906c3fb27SDimitry Andric DECLARE_REAL(void *, memcpy, void *to, const void *from, SIZE_T size)
4006c3fb27SDimitry Andric DECLARE_REAL(void *, memset, void *block, int c, SIZE_T size)
4106c3fb27SDimitry Andric 
4281ad6265SDimitry Andric #if SANITIZER_FREEBSD || SANITIZER_APPLE
4368d75effSDimitry Andric #define stdout __stdoutp
4468d75effSDimitry Andric #define stderr __stderrp
4568d75effSDimitry Andric #endif
4668d75effSDimitry Andric 
4768d75effSDimitry Andric #if SANITIZER_NETBSD
4868d75effSDimitry Andric #define dirfd(dirp) (*(int *)(dirp))
4968d75effSDimitry Andric #define fileno_unlocked(fp)              \
5068d75effSDimitry Andric   (((__sanitizer_FILE *)fp)->_file == -1 \
5168d75effSDimitry Andric        ? -1                              \
5268d75effSDimitry Andric        : (int)(unsigned short)(((__sanitizer_FILE *)fp)->_file))
5368d75effSDimitry Andric 
5468d75effSDimitry Andric #define stdout ((__sanitizer_FILE*)&__sF[1])
5568d75effSDimitry Andric #define stderr ((__sanitizer_FILE*)&__sF[2])
5668d75effSDimitry Andric 
5768d75effSDimitry Andric #define nanosleep __nanosleep50
5868d75effSDimitry Andric #define vfork __vfork14
5968d75effSDimitry Andric #endif
6068d75effSDimitry Andric 
6168d75effSDimitry Andric #ifdef __mips__
6268d75effSDimitry Andric const int kSigCount = 129;
6368d75effSDimitry Andric #else
6468d75effSDimitry Andric const int kSigCount = 65;
6568d75effSDimitry Andric #endif
6668d75effSDimitry Andric 
6768d75effSDimitry Andric #ifdef __mips__
6868d75effSDimitry Andric struct ucontext_t {
6968d75effSDimitry Andric   u64 opaque[768 / sizeof(u64) + 1];
7068d75effSDimitry Andric };
7168d75effSDimitry Andric #else
7268d75effSDimitry Andric struct ucontext_t {
7368d75effSDimitry Andric   // The size is determined by looking at sizeof of real ucontext_t on linux.
7468d75effSDimitry Andric   u64 opaque[936 / sizeof(u64) + 1];
7568d75effSDimitry Andric };
7668d75effSDimitry Andric #endif
7768d75effSDimitry Andric 
78fe6060f1SDimitry Andric #if defined(__x86_64__) || defined(__mips__) || SANITIZER_PPC64V1 || \
79fe6060f1SDimitry Andric     defined(__s390x__)
8068d75effSDimitry Andric #define PTHREAD_ABI_BASE  "GLIBC_2.3.2"
8168d75effSDimitry Andric #elif defined(__aarch64__) || SANITIZER_PPC64V2
8268d75effSDimitry Andric #define PTHREAD_ABI_BASE  "GLIBC_2.17"
83bdd1243dSDimitry Andric #elif SANITIZER_LOONGARCH64
84bdd1243dSDimitry Andric #define PTHREAD_ABI_BASE  "GLIBC_2.36"
855f757f3fSDimitry Andric #elif SANITIZER_RISCV64
865f757f3fSDimitry Andric #  define PTHREAD_ABI_BASE "GLIBC_2.27"
8768d75effSDimitry Andric #endif
8868d75effSDimitry Andric 
8968d75effSDimitry Andric extern "C" int pthread_attr_init(void *attr);
9068d75effSDimitry Andric extern "C" int pthread_attr_destroy(void *attr);
9168d75effSDimitry Andric DECLARE_REAL(int, pthread_attr_getdetachstate, void *, void *)
9268d75effSDimitry Andric extern "C" int pthread_attr_setstacksize(void *attr, uptr stacksize);
93fe6060f1SDimitry Andric extern "C" int pthread_atfork(void (*prepare)(void), void (*parent)(void),
94fe6060f1SDimitry Andric                               void (*child)(void));
9568d75effSDimitry Andric extern "C" int pthread_key_create(unsigned *key, void (*destructor)(void* v));
9668d75effSDimitry Andric extern "C" int pthread_setspecific(unsigned key, const void *v);
9768d75effSDimitry Andric DECLARE_REAL(int, pthread_mutexattr_gettype, void *, void *)
9868d75effSDimitry Andric DECLARE_REAL(int, fflush, __sanitizer_FILE *fp)
9968d75effSDimitry Andric DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, uptr size)
10068d75effSDimitry Andric DECLARE_REAL_AND_INTERCEPTOR(void, free, void *ptr)
101349cc55cSDimitry Andric extern "C" int pthread_equal(void *t1, void *t2);
10268d75effSDimitry Andric extern "C" void *pthread_self();
10368d75effSDimitry Andric extern "C" void _exit(int status);
10468d75effSDimitry Andric #if !SANITIZER_NETBSD
10568d75effSDimitry Andric extern "C" int fileno_unlocked(void *stream);
10668d75effSDimitry Andric extern "C" int dirfd(void *dirp);
10768d75effSDimitry Andric #endif
10868d75effSDimitry Andric #if SANITIZER_NETBSD
10968d75effSDimitry Andric extern __sanitizer_FILE __sF[];
11068d75effSDimitry Andric #else
11168d75effSDimitry Andric extern __sanitizer_FILE *stdout, *stderr;
11268d75effSDimitry Andric #endif
11381ad6265SDimitry Andric #if !SANITIZER_FREEBSD && !SANITIZER_APPLE && !SANITIZER_NETBSD
11468d75effSDimitry Andric const int PTHREAD_MUTEX_RECURSIVE = 1;
11568d75effSDimitry Andric const int PTHREAD_MUTEX_RECURSIVE_NP = 1;
11668d75effSDimitry Andric #else
11768d75effSDimitry Andric const int PTHREAD_MUTEX_RECURSIVE = 2;
11868d75effSDimitry Andric const int PTHREAD_MUTEX_RECURSIVE_NP = 2;
11968d75effSDimitry Andric #endif
12081ad6265SDimitry Andric #if !SANITIZER_FREEBSD && !SANITIZER_APPLE && !SANITIZER_NETBSD
12168d75effSDimitry Andric const int EPOLL_CTL_ADD = 1;
12268d75effSDimitry Andric #endif
12368d75effSDimitry Andric const int SIGILL = 4;
12468d75effSDimitry Andric const int SIGTRAP = 5;
12568d75effSDimitry Andric const int SIGABRT = 6;
12668d75effSDimitry Andric const int SIGFPE = 8;
12768d75effSDimitry Andric const int SIGSEGV = 11;
12868d75effSDimitry Andric const int SIGPIPE = 13;
12968d75effSDimitry Andric const int SIGTERM = 15;
13081ad6265SDimitry Andric #if defined(__mips__) || SANITIZER_FREEBSD || SANITIZER_APPLE || SANITIZER_NETBSD
13168d75effSDimitry Andric const int SIGBUS = 10;
13268d75effSDimitry Andric const int SIGSYS = 12;
13368d75effSDimitry Andric #else
13468d75effSDimitry Andric const int SIGBUS = 7;
13568d75effSDimitry Andric const int SIGSYS = 31;
13668d75effSDimitry Andric #endif
13706c3fb27SDimitry Andric #if SANITIZER_HAS_SIGINFO
138bdd1243dSDimitry Andric const int SI_TIMER = -2;
13906c3fb27SDimitry Andric #endif
14068d75effSDimitry Andric void *const MAP_FAILED = (void*)-1;
14168d75effSDimitry Andric #if SANITIZER_NETBSD
14268d75effSDimitry Andric const int PTHREAD_BARRIER_SERIAL_THREAD = 1234567;
14381ad6265SDimitry Andric #elif !SANITIZER_APPLE
14468d75effSDimitry Andric const int PTHREAD_BARRIER_SERIAL_THREAD = -1;
14568d75effSDimitry Andric #endif
14668d75effSDimitry Andric const int MAP_FIXED = 0x10;
14768d75effSDimitry Andric typedef long long_t;
148e8d8bef9SDimitry Andric typedef __sanitizer::u16 mode_t;
14968d75effSDimitry Andric 
15068d75effSDimitry Andric // From /usr/include/unistd.h
15168d75effSDimitry Andric # define F_ULOCK 0      /* Unlock a previously locked region.  */
15268d75effSDimitry Andric # define F_LOCK  1      /* Lock a region for exclusive use.  */
15368d75effSDimitry Andric # define F_TLOCK 2      /* Test and lock a region for exclusive use.  */
15468d75effSDimitry Andric # define F_TEST  3      /* Test a region for other processes locks.  */
15568d75effSDimitry Andric 
15681ad6265SDimitry Andric #if SANITIZER_FREEBSD || SANITIZER_APPLE || SANITIZER_NETBSD
15768d75effSDimitry Andric const int SA_SIGINFO = 0x40;
15868d75effSDimitry Andric const int SIG_SETMASK = 3;
15968d75effSDimitry Andric #elif defined(__mips__)
16068d75effSDimitry Andric const int SA_SIGINFO = 8;
16168d75effSDimitry Andric const int SIG_SETMASK = 3;
16268d75effSDimitry Andric #else
16368d75effSDimitry Andric const int SA_SIGINFO = 4;
16468d75effSDimitry Andric const int SIG_SETMASK = 2;
16568d75effSDimitry Andric #endif
16668d75effSDimitry Andric 
16768d75effSDimitry Andric namespace __tsan {
16868d75effSDimitry Andric struct SignalDesc {
16968d75effSDimitry Andric   bool armed;
17068d75effSDimitry Andric   __sanitizer_siginfo siginfo;
17168d75effSDimitry Andric   ucontext_t ctx;
17268d75effSDimitry Andric };
17368d75effSDimitry Andric 
17468d75effSDimitry Andric struct ThreadSignalContext {
17568d75effSDimitry Andric   int int_signal_send;
17668d75effSDimitry Andric   SignalDesc pending_signals[kSigCount];
17768d75effSDimitry Andric   // emptyset and oldset are too big for stack.
17868d75effSDimitry Andric   __sanitizer_sigset_t emptyset;
17968d75effSDimitry Andric   __sanitizer_sigset_t oldset;
18068d75effSDimitry Andric };
18168d75effSDimitry Andric 
182bdd1243dSDimitry Andric void EnterBlockingFunc(ThreadState *thr) {
183bdd1243dSDimitry Andric   for (;;) {
184bdd1243dSDimitry Andric     // The order is important to not delay a signal infinitely if it's
185bdd1243dSDimitry Andric     // delivered right before we set in_blocking_func. Note: we can't call
186bdd1243dSDimitry Andric     // ProcessPendingSignals when in_blocking_func is set, or we can handle
187bdd1243dSDimitry Andric     // a signal synchronously when we are already handling a signal.
188bdd1243dSDimitry Andric     atomic_store(&thr->in_blocking_func, 1, memory_order_relaxed);
189bdd1243dSDimitry Andric     if (atomic_load(&thr->pending_signals, memory_order_relaxed) == 0)
190bdd1243dSDimitry Andric       break;
191bdd1243dSDimitry Andric     atomic_store(&thr->in_blocking_func, 0, memory_order_relaxed);
192bdd1243dSDimitry Andric     ProcessPendingSignals(thr);
193bdd1243dSDimitry Andric   }
194bdd1243dSDimitry Andric }
195bdd1243dSDimitry Andric 
19668d75effSDimitry Andric // The sole reason tsan wraps atexit callbacks is to establish synchronization
19768d75effSDimitry Andric // between callback setup and callback execution.
19868d75effSDimitry Andric struct AtExitCtx {
19968d75effSDimitry Andric   void (*f)();
20068d75effSDimitry Andric   void *arg;
2014824e7fdSDimitry Andric   uptr pc;
20268d75effSDimitry Andric };
20368d75effSDimitry Andric 
20468d75effSDimitry Andric // InterceptorContext holds all global data required for interceptors.
20568d75effSDimitry Andric // It's explicitly constructed in InitializeInterceptors with placement new
20668d75effSDimitry Andric // and is never destroyed. This allows usage of members with non-trivial
20768d75effSDimitry Andric // constructors and destructors.
20868d75effSDimitry Andric struct InterceptorContext {
20968d75effSDimitry Andric   // The object is 64-byte aligned, because we want hot data to be located
21068d75effSDimitry Andric   // in a single cache line if possible (it's accessed in every interceptor).
211*0fca6ea1SDimitry Andric   alignas(64) LibIgnore libignore;
21268d75effSDimitry Andric   __sanitizer_sigaction sigactions[kSigCount];
21381ad6265SDimitry Andric #if !SANITIZER_APPLE && !SANITIZER_NETBSD
21468d75effSDimitry Andric   unsigned finalize_key;
21568d75effSDimitry Andric #endif
21668d75effSDimitry Andric 
217fe6060f1SDimitry Andric   Mutex atexit_mu;
21868d75effSDimitry Andric   Vector<struct AtExitCtx *> AtExitStack;
21968d75effSDimitry Andric 
220fe6060f1SDimitry Andric   InterceptorContext() : libignore(LINKER_INITIALIZED), atexit_mu(MutexTypeAtExit), AtExitStack() {}
22168d75effSDimitry Andric };
22268d75effSDimitry Andric 
223*0fca6ea1SDimitry Andric alignas(64) static char interceptor_placeholder[sizeof(InterceptorContext)];
22468d75effSDimitry Andric InterceptorContext *interceptor_ctx() {
22568d75effSDimitry Andric   return reinterpret_cast<InterceptorContext*>(&interceptor_placeholder[0]);
22668d75effSDimitry Andric }
22768d75effSDimitry Andric 
22868d75effSDimitry Andric LibIgnore *libignore() {
22968d75effSDimitry Andric   return &interceptor_ctx()->libignore;
23068d75effSDimitry Andric }
23168d75effSDimitry Andric 
23268d75effSDimitry Andric void InitializeLibIgnore() {
23368d75effSDimitry Andric   const SuppressionContext &supp = *Suppressions();
23468d75effSDimitry Andric   const uptr n = supp.SuppressionCount();
23568d75effSDimitry Andric   for (uptr i = 0; i < n; i++) {
23668d75effSDimitry Andric     const Suppression *s = supp.SuppressionAt(i);
23768d75effSDimitry Andric     if (0 == internal_strcmp(s->type, kSuppressionLib))
23868d75effSDimitry Andric       libignore()->AddIgnoredLibrary(s->templ);
23968d75effSDimitry Andric   }
24068d75effSDimitry Andric   if (flags()->ignore_noninstrumented_modules)
24168d75effSDimitry Andric     libignore()->IgnoreNoninstrumentedModules(true);
24268d75effSDimitry Andric   libignore()->OnLibraryLoaded(0);
24368d75effSDimitry Andric }
24468d75effSDimitry Andric 
24568d75effSDimitry Andric // The following two hooks can be used by for cooperative scheduling when
24668d75effSDimitry Andric // locking.
24768d75effSDimitry Andric #ifdef TSAN_EXTERNAL_HOOKS
24868d75effSDimitry Andric void OnPotentiallyBlockingRegionBegin();
24968d75effSDimitry Andric void OnPotentiallyBlockingRegionEnd();
25068d75effSDimitry Andric #else
25168d75effSDimitry Andric SANITIZER_WEAK_CXX_DEFAULT_IMPL void OnPotentiallyBlockingRegionBegin() {}
25268d75effSDimitry Andric SANITIZER_WEAK_CXX_DEFAULT_IMPL void OnPotentiallyBlockingRegionEnd() {}
25368d75effSDimitry Andric #endif
25468d75effSDimitry Andric 
25568d75effSDimitry Andric }  // namespace __tsan
25668d75effSDimitry Andric 
25768d75effSDimitry Andric static ThreadSignalContext *SigCtx(ThreadState *thr) {
258bdd1243dSDimitry Andric   // This function may be called reentrantly if it is interrupted by a signal
259bdd1243dSDimitry Andric   // handler. Use CAS to handle the race.
260bdd1243dSDimitry Andric   uptr ctx = atomic_load(&thr->signal_ctx, memory_order_relaxed);
26168d75effSDimitry Andric   if (ctx == 0 && !thr->is_dead) {
262bdd1243dSDimitry Andric     uptr pctx =
263bdd1243dSDimitry Andric         (uptr)MmapOrDie(sizeof(ThreadSignalContext), "ThreadSignalContext");
264bdd1243dSDimitry Andric     MemoryResetRange(thr, (uptr)&SigCtx, pctx, sizeof(ThreadSignalContext));
265bdd1243dSDimitry Andric     if (atomic_compare_exchange_strong(&thr->signal_ctx, &ctx, pctx,
266bdd1243dSDimitry Andric                                        memory_order_relaxed)) {
267bdd1243dSDimitry Andric       ctx = pctx;
268bdd1243dSDimitry Andric     } else {
269bdd1243dSDimitry Andric       UnmapOrDie((ThreadSignalContext *)pctx, sizeof(ThreadSignalContext));
27068d75effSDimitry Andric     }
271bdd1243dSDimitry Andric   }
272bdd1243dSDimitry Andric   return (ThreadSignalContext *)ctx;
27368d75effSDimitry Andric }
27468d75effSDimitry Andric 
27568d75effSDimitry Andric ScopedInterceptor::ScopedInterceptor(ThreadState *thr, const char *fname,
27668d75effSDimitry Andric                                      uptr pc)
277bdd1243dSDimitry Andric     : thr_(thr) {
278349cc55cSDimitry Andric   LazyInitialize(thr);
279bdd1243dSDimitry Andric   if (UNLIKELY(atomic_load(&thr->in_blocking_func, memory_order_relaxed))) {
280bdd1243dSDimitry Andric     // pthread_join is marked as blocking, but it's also known to call other
281bdd1243dSDimitry Andric     // intercepted functions (mmap, free). If we don't reset in_blocking_func
282bdd1243dSDimitry Andric     // we can get deadlocks and memory corruptions if we deliver a synchronous
283bdd1243dSDimitry Andric     // signal inside of an mmap/free interceptor.
284bdd1243dSDimitry Andric     // So reset it and restore it back in the destructor.
285bdd1243dSDimitry Andric     // See https://github.com/google/sanitizers/issues/1540
286bdd1243dSDimitry Andric     atomic_store(&thr->in_blocking_func, 0, memory_order_relaxed);
287bdd1243dSDimitry Andric     in_blocking_func_ = true;
288bdd1243dSDimitry Andric   }
28968d75effSDimitry Andric   if (!thr_->is_inited) return;
29068d75effSDimitry Andric   if (!thr_->ignore_interceptors) FuncEntry(thr, pc);
29168d75effSDimitry Andric   DPrintf("#%d: intercept %s()\n", thr_->tid, fname);
29268d75effSDimitry Andric   ignoring_ =
2935ffd83dbSDimitry Andric       !thr_->in_ignored_lib && (flags()->ignore_interceptors_accesses ||
2945ffd83dbSDimitry Andric                                 libignore()->IsIgnored(pc, &in_ignored_lib_));
29568d75effSDimitry Andric   EnableIgnores();
29668d75effSDimitry Andric }
29768d75effSDimitry Andric 
29868d75effSDimitry Andric ScopedInterceptor::~ScopedInterceptor() {
29968d75effSDimitry Andric   if (!thr_->is_inited) return;
30068d75effSDimitry Andric   DisableIgnores();
301bdd1243dSDimitry Andric   if (UNLIKELY(in_blocking_func_))
302bdd1243dSDimitry Andric     EnterBlockingFunc(thr_);
30368d75effSDimitry Andric   if (!thr_->ignore_interceptors) {
30468d75effSDimitry Andric     ProcessPendingSignals(thr_);
30568d75effSDimitry Andric     FuncExit(thr_);
306fe6060f1SDimitry Andric     CheckedMutex::CheckNoLocks();
30768d75effSDimitry Andric   }
30868d75effSDimitry Andric }
30968d75effSDimitry Andric 
310349cc55cSDimitry Andric NOINLINE
311349cc55cSDimitry Andric void ScopedInterceptor::EnableIgnoresImpl() {
312349cc55cSDimitry Andric   ThreadIgnoreBegin(thr_, 0);
313349cc55cSDimitry Andric   if (flags()->ignore_noninstrumented_modules)
314349cc55cSDimitry Andric     thr_->suppress_reports++;
31568d75effSDimitry Andric   if (in_ignored_lib_) {
31668d75effSDimitry Andric     DCHECK(!thr_->in_ignored_lib);
31768d75effSDimitry Andric     thr_->in_ignored_lib = true;
31868d75effSDimitry Andric   }
31968d75effSDimitry Andric }
32068d75effSDimitry Andric 
321349cc55cSDimitry Andric NOINLINE
322349cc55cSDimitry Andric void ScopedInterceptor::DisableIgnoresImpl() {
323349cc55cSDimitry Andric   ThreadIgnoreEnd(thr_);
324349cc55cSDimitry Andric   if (flags()->ignore_noninstrumented_modules)
325349cc55cSDimitry Andric     thr_->suppress_reports--;
32668d75effSDimitry Andric   if (in_ignored_lib_) {
32768d75effSDimitry Andric     DCHECK(thr_->in_ignored_lib);
32868d75effSDimitry Andric     thr_->in_ignored_lib = false;
32968d75effSDimitry Andric   }
33068d75effSDimitry Andric }
33168d75effSDimitry Andric 
33268d75effSDimitry Andric #define TSAN_INTERCEPT(func) INTERCEPT_FUNCTION(func)
3331c21bfb1SDimitry Andric #if SANITIZER_FREEBSD || SANITIZER_NETBSD
3341c21bfb1SDimitry Andric #  define TSAN_INTERCEPT_VER(func, ver) INTERCEPT_FUNCTION(func)
3351c21bfb1SDimitry Andric #else
3361c21bfb1SDimitry Andric #  define TSAN_INTERCEPT_VER(func, ver) INTERCEPT_FUNCTION_VER(func, ver)
3371c21bfb1SDimitry Andric #endif
33868d75effSDimitry Andric #if SANITIZER_FREEBSD
3391c21bfb1SDimitry Andric #  define TSAN_MAYBE_INTERCEPT_FREEBSD_ALIAS(func) \
3401c21bfb1SDimitry Andric     INTERCEPT_FUNCTION(_pthread_##func)
3411c21bfb1SDimitry Andric #else
3421c21bfb1SDimitry Andric #  define TSAN_MAYBE_INTERCEPT_FREEBSD_ALIAS(func)
3431c21bfb1SDimitry Andric #endif
3441c21bfb1SDimitry Andric #if SANITIZER_NETBSD
34568d75effSDimitry Andric #  define TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(func) \
34668d75effSDimitry Andric     INTERCEPT_FUNCTION(__libc_##func)
34768d75effSDimitry Andric #  define TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS_THR(func) \
34868d75effSDimitry Andric     INTERCEPT_FUNCTION(__libc_thr_##func)
34968d75effSDimitry Andric #else
35068d75effSDimitry Andric #  define TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(func)
35168d75effSDimitry Andric #  define TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS_THR(func)
35268d75effSDimitry Andric #endif
35368d75effSDimitry Andric 
35468d75effSDimitry Andric #define READ_STRING_OF_LEN(thr, pc, s, len, n)                 \
35568d75effSDimitry Andric   MemoryAccessRange((thr), (pc), (uptr)(s),                         \
35668d75effSDimitry Andric     common_flags()->strict_string_checks ? (len) + 1 : (n), false)
35768d75effSDimitry Andric 
35868d75effSDimitry Andric #define READ_STRING(thr, pc, s, n)                             \
35968d75effSDimitry Andric     READ_STRING_OF_LEN((thr), (pc), (s), internal_strlen(s), (n))
36068d75effSDimitry Andric 
36168d75effSDimitry Andric #define BLOCK_REAL(name) (BlockingCall(thr), REAL(name))
36268d75effSDimitry Andric 
36368d75effSDimitry Andric struct BlockingCall {
36468d75effSDimitry Andric   explicit BlockingCall(ThreadState *thr)
365bdd1243dSDimitry Andric       : thr(thr) {
366bdd1243dSDimitry Andric     EnterBlockingFunc(thr);
36768d75effSDimitry Andric     // When we are in a "blocking call", we process signals asynchronously
36868d75effSDimitry Andric     // (right when they arrive). In this context we do not expect to be
36968d75effSDimitry Andric     // executing any user/runtime code. The known interceptor sequence when
37068d75effSDimitry Andric     // this is not true is: pthread_join -> munmap(stack). It's fine
37168d75effSDimitry Andric     // to ignore munmap in this case -- we handle stack shadow separately.
37268d75effSDimitry Andric     thr->ignore_interceptors++;
37368d75effSDimitry Andric   }
37468d75effSDimitry Andric 
37568d75effSDimitry Andric   ~BlockingCall() {
37668d75effSDimitry Andric     thr->ignore_interceptors--;
377bdd1243dSDimitry Andric     atomic_store(&thr->in_blocking_func, 0, memory_order_relaxed);
37868d75effSDimitry Andric   }
37968d75effSDimitry Andric 
38068d75effSDimitry Andric   ThreadState *thr;
38168d75effSDimitry Andric };
38268d75effSDimitry Andric 
38368d75effSDimitry Andric TSAN_INTERCEPTOR(unsigned, sleep, unsigned sec) {
38468d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(sleep, sec);
38568d75effSDimitry Andric   unsigned res = BLOCK_REAL(sleep)(sec);
38668d75effSDimitry Andric   AfterSleep(thr, pc);
38768d75effSDimitry Andric   return res;
38868d75effSDimitry Andric }
38968d75effSDimitry Andric 
39068d75effSDimitry Andric TSAN_INTERCEPTOR(int, usleep, long_t usec) {
39168d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(usleep, usec);
39268d75effSDimitry Andric   int res = BLOCK_REAL(usleep)(usec);
39368d75effSDimitry Andric   AfterSleep(thr, pc);
39468d75effSDimitry Andric   return res;
39568d75effSDimitry Andric }
39668d75effSDimitry Andric 
39768d75effSDimitry Andric TSAN_INTERCEPTOR(int, nanosleep, void *req, void *rem) {
39868d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(nanosleep, req, rem);
39968d75effSDimitry Andric   int res = BLOCK_REAL(nanosleep)(req, rem);
40068d75effSDimitry Andric   AfterSleep(thr, pc);
40168d75effSDimitry Andric   return res;
40268d75effSDimitry Andric }
40368d75effSDimitry Andric 
40468d75effSDimitry Andric TSAN_INTERCEPTOR(int, pause, int fake) {
40568d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(pause, fake);
40668d75effSDimitry Andric   return BLOCK_REAL(pause)(fake);
40768d75effSDimitry Andric }
40868d75effSDimitry Andric 
4094824e7fdSDimitry Andric // Note: we specifically call the function in such strange way
4104824e7fdSDimitry Andric // with "installed_at" because in reports it will appear between
4114824e7fdSDimitry Andric // callback frames and the frame that installed the callback.
4124824e7fdSDimitry Andric static void at_exit_callback_installed_at() {
41368d75effSDimitry Andric   AtExitCtx *ctx;
41468d75effSDimitry Andric   {
41568d75effSDimitry Andric     // Ensure thread-safety.
416fe6060f1SDimitry Andric     Lock l(&interceptor_ctx()->atexit_mu);
41768d75effSDimitry Andric 
41868d75effSDimitry Andric     // Pop AtExitCtx from the top of the stack of callback functions
41968d75effSDimitry Andric     uptr element = interceptor_ctx()->AtExitStack.Size() - 1;
42068d75effSDimitry Andric     ctx = interceptor_ctx()->AtExitStack[element];
42168d75effSDimitry Andric     interceptor_ctx()->AtExitStack.PopBack();
42268d75effSDimitry Andric   }
42368d75effSDimitry Andric 
4244824e7fdSDimitry Andric   ThreadState *thr = cur_thread();
4254824e7fdSDimitry Andric   Acquire(thr, ctx->pc, (uptr)ctx);
4264824e7fdSDimitry Andric   FuncEntry(thr, ctx->pc);
42768d75effSDimitry Andric   ((void(*)())ctx->f)();
4284824e7fdSDimitry Andric   FuncExit(thr);
429349cc55cSDimitry Andric   Free(ctx);
43068d75effSDimitry Andric }
43168d75effSDimitry Andric 
4324824e7fdSDimitry Andric static void cxa_at_exit_callback_installed_at(void *arg) {
4334824e7fdSDimitry Andric   ThreadState *thr = cur_thread();
43468d75effSDimitry Andric   AtExitCtx *ctx = (AtExitCtx*)arg;
4354824e7fdSDimitry Andric   Acquire(thr, ctx->pc, (uptr)arg);
4364824e7fdSDimitry Andric   FuncEntry(thr, ctx->pc);
43768d75effSDimitry Andric   ((void(*)(void *arg))ctx->f)(ctx->arg);
4384824e7fdSDimitry Andric   FuncExit(thr);
439349cc55cSDimitry Andric   Free(ctx);
44068d75effSDimitry Andric }
44168d75effSDimitry Andric 
44268d75effSDimitry Andric static int setup_at_exit_wrapper(ThreadState *thr, uptr pc, void(*f)(),
44368d75effSDimitry Andric       void *arg, void *dso);
44468d75effSDimitry Andric 
44568d75effSDimitry Andric #if !SANITIZER_ANDROID
44668d75effSDimitry Andric TSAN_INTERCEPTOR(int, atexit, void (*f)()) {
44768d75effSDimitry Andric   if (in_symbolizer())
44868d75effSDimitry Andric     return 0;
44968d75effSDimitry Andric   // We want to setup the atexit callback even if we are in ignored lib
45068d75effSDimitry Andric   // or after fork.
45168d75effSDimitry Andric   SCOPED_INTERCEPTOR_RAW(atexit, f);
4524824e7fdSDimitry Andric   return setup_at_exit_wrapper(thr, GET_CALLER_PC(), (void (*)())f, 0, 0);
45368d75effSDimitry Andric }
45468d75effSDimitry Andric #endif
45568d75effSDimitry Andric 
45668d75effSDimitry Andric TSAN_INTERCEPTOR(int, __cxa_atexit, void (*f)(void *a), void *arg, void *dso) {
45768d75effSDimitry Andric   if (in_symbolizer())
45868d75effSDimitry Andric     return 0;
45968d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(__cxa_atexit, f, arg, dso);
4604824e7fdSDimitry Andric   return setup_at_exit_wrapper(thr, GET_CALLER_PC(), (void (*)())f, arg, dso);
46168d75effSDimitry Andric }
46268d75effSDimitry Andric 
46368d75effSDimitry Andric static int setup_at_exit_wrapper(ThreadState *thr, uptr pc, void(*f)(),
46468d75effSDimitry Andric       void *arg, void *dso) {
465349cc55cSDimitry Andric   auto *ctx = New<AtExitCtx>();
46668d75effSDimitry Andric   ctx->f = f;
46768d75effSDimitry Andric   ctx->arg = arg;
4684824e7fdSDimitry Andric   ctx->pc = pc;
46968d75effSDimitry Andric   Release(thr, pc, (uptr)ctx);
47068d75effSDimitry Andric   // Memory allocation in __cxa_atexit will race with free during exit,
47168d75effSDimitry Andric   // because we do not see synchronization around atexit callback list.
47268d75effSDimitry Andric   ThreadIgnoreBegin(thr, pc);
47368d75effSDimitry Andric   int res;
47468d75effSDimitry Andric   if (!dso) {
47568d75effSDimitry Andric     // NetBSD does not preserve the 2nd argument if dso is equal to 0
47668d75effSDimitry Andric     // Store ctx in a local stack-like structure
47768d75effSDimitry Andric 
47868d75effSDimitry Andric     // Ensure thread-safety.
479fe6060f1SDimitry Andric     Lock l(&interceptor_ctx()->atexit_mu);
480fe6060f1SDimitry Andric     // __cxa_atexit calls calloc. If we don't ignore interceptors, we will fail
481fe6060f1SDimitry Andric     // due to atexit_mu held on exit from the calloc interceptor.
482fe6060f1SDimitry Andric     ScopedIgnoreInterceptors ignore;
48368d75effSDimitry Andric 
4844824e7fdSDimitry Andric     res = REAL(__cxa_atexit)((void (*)(void *a))at_exit_callback_installed_at,
4854824e7fdSDimitry Andric                              0, 0);
48668d75effSDimitry Andric     // Push AtExitCtx on the top of the stack of callback functions
48768d75effSDimitry Andric     if (!res) {
48868d75effSDimitry Andric       interceptor_ctx()->AtExitStack.PushBack(ctx);
48968d75effSDimitry Andric     }
49068d75effSDimitry Andric   } else {
4914824e7fdSDimitry Andric     res = REAL(__cxa_atexit)(cxa_at_exit_callback_installed_at, ctx, dso);
49268d75effSDimitry Andric   }
493349cc55cSDimitry Andric   ThreadIgnoreEnd(thr);
49468d75effSDimitry Andric   return res;
49568d75effSDimitry Andric }
49668d75effSDimitry Andric 
49781ad6265SDimitry Andric #if !SANITIZER_APPLE && !SANITIZER_NETBSD
4984824e7fdSDimitry Andric static void on_exit_callback_installed_at(int status, void *arg) {
49968d75effSDimitry Andric   ThreadState *thr = cur_thread();
50068d75effSDimitry Andric   AtExitCtx *ctx = (AtExitCtx*)arg;
5014824e7fdSDimitry Andric   Acquire(thr, ctx->pc, (uptr)arg);
5024824e7fdSDimitry Andric   FuncEntry(thr, ctx->pc);
50368d75effSDimitry Andric   ((void(*)(int status, void *arg))ctx->f)(status, ctx->arg);
5044824e7fdSDimitry Andric   FuncExit(thr);
505349cc55cSDimitry Andric   Free(ctx);
50668d75effSDimitry Andric }
50768d75effSDimitry Andric 
50868d75effSDimitry Andric TSAN_INTERCEPTOR(int, on_exit, void(*f)(int, void*), void *arg) {
50968d75effSDimitry Andric   if (in_symbolizer())
51068d75effSDimitry Andric     return 0;
51168d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(on_exit, f, arg);
512349cc55cSDimitry Andric   auto *ctx = New<AtExitCtx>();
51368d75effSDimitry Andric   ctx->f = (void(*)())f;
51468d75effSDimitry Andric   ctx->arg = arg;
5154824e7fdSDimitry Andric   ctx->pc = GET_CALLER_PC();
51668d75effSDimitry Andric   Release(thr, pc, (uptr)ctx);
51768d75effSDimitry Andric   // Memory allocation in __cxa_atexit will race with free during exit,
51868d75effSDimitry Andric   // because we do not see synchronization around atexit callback list.
51968d75effSDimitry Andric   ThreadIgnoreBegin(thr, pc);
5204824e7fdSDimitry Andric   int res = REAL(on_exit)(on_exit_callback_installed_at, ctx);
521349cc55cSDimitry Andric   ThreadIgnoreEnd(thr);
52268d75effSDimitry Andric   return res;
52368d75effSDimitry Andric }
52468d75effSDimitry Andric #define TSAN_MAYBE_INTERCEPT_ON_EXIT TSAN_INTERCEPT(on_exit)
52568d75effSDimitry Andric #else
52668d75effSDimitry Andric #define TSAN_MAYBE_INTERCEPT_ON_EXIT
52768d75effSDimitry Andric #endif
52868d75effSDimitry Andric 
52968d75effSDimitry Andric // Cleanup old bufs.
53068d75effSDimitry Andric static void JmpBufGarbageCollect(ThreadState *thr, uptr sp) {
53168d75effSDimitry Andric   for (uptr i = 0; i < thr->jmp_bufs.Size(); i++) {
53268d75effSDimitry Andric     JmpBuf *buf = &thr->jmp_bufs[i];
53368d75effSDimitry Andric     if (buf->sp <= sp) {
53468d75effSDimitry Andric       uptr sz = thr->jmp_bufs.Size();
53568d75effSDimitry Andric       internal_memcpy(buf, &thr->jmp_bufs[sz - 1], sizeof(*buf));
53668d75effSDimitry Andric       thr->jmp_bufs.PopBack();
53768d75effSDimitry Andric       i--;
53868d75effSDimitry Andric     }
53968d75effSDimitry Andric   }
54068d75effSDimitry Andric }
54168d75effSDimitry Andric 
54268d75effSDimitry Andric static void SetJmp(ThreadState *thr, uptr sp) {
54368d75effSDimitry Andric   if (!thr->is_inited)  // called from libc guts during bootstrap
54468d75effSDimitry Andric     return;
54568d75effSDimitry Andric   // Cleanup old bufs.
54668d75effSDimitry Andric   JmpBufGarbageCollect(thr, sp);
54768d75effSDimitry Andric   // Remember the buf.
54868d75effSDimitry Andric   JmpBuf *buf = thr->jmp_bufs.PushBack();
54968d75effSDimitry Andric   buf->sp = sp;
55068d75effSDimitry Andric   buf->shadow_stack_pos = thr->shadow_stack_pos;
55168d75effSDimitry Andric   ThreadSignalContext *sctx = SigCtx(thr);
55268d75effSDimitry Andric   buf->int_signal_send = sctx ? sctx->int_signal_send : 0;
553bdd1243dSDimitry Andric   buf->in_blocking_func = atomic_load(&thr->in_blocking_func, memory_order_relaxed);
55468d75effSDimitry Andric   buf->in_signal_handler = atomic_load(&thr->in_signal_handler,
55568d75effSDimitry Andric       memory_order_relaxed);
55668d75effSDimitry Andric }
55768d75effSDimitry Andric 
55868d75effSDimitry Andric static void LongJmp(ThreadState *thr, uptr *env) {
55968d75effSDimitry Andric   uptr sp = ExtractLongJmpSp(env);
56068d75effSDimitry Andric   // Find the saved buf with matching sp.
56168d75effSDimitry Andric   for (uptr i = 0; i < thr->jmp_bufs.Size(); i++) {
56268d75effSDimitry Andric     JmpBuf *buf = &thr->jmp_bufs[i];
56368d75effSDimitry Andric     if (buf->sp == sp) {
56468d75effSDimitry Andric       CHECK_GE(thr->shadow_stack_pos, buf->shadow_stack_pos);
56568d75effSDimitry Andric       // Unwind the stack.
56668d75effSDimitry Andric       while (thr->shadow_stack_pos > buf->shadow_stack_pos)
56768d75effSDimitry Andric         FuncExit(thr);
56868d75effSDimitry Andric       ThreadSignalContext *sctx = SigCtx(thr);
569bdd1243dSDimitry Andric       if (sctx)
57068d75effSDimitry Andric         sctx->int_signal_send = buf->int_signal_send;
571bdd1243dSDimitry Andric       atomic_store(&thr->in_blocking_func, buf->in_blocking_func,
57268d75effSDimitry Andric           memory_order_relaxed);
57368d75effSDimitry Andric       atomic_store(&thr->in_signal_handler, buf->in_signal_handler,
57468d75effSDimitry Andric           memory_order_relaxed);
57568d75effSDimitry Andric       JmpBufGarbageCollect(thr, buf->sp - 1);  // do not collect buf->sp
57668d75effSDimitry Andric       return;
57768d75effSDimitry Andric     }
57868d75effSDimitry Andric   }
57968d75effSDimitry Andric   Printf("ThreadSanitizer: can't find longjmp buf\n");
58068d75effSDimitry Andric   CHECK(0);
58168d75effSDimitry Andric }
58268d75effSDimitry Andric 
58368d75effSDimitry Andric // FIXME: put everything below into a common extern "C" block?
584349cc55cSDimitry Andric extern "C" void __tsan_setjmp(uptr sp) { SetJmp(cur_thread_init(), sp); }
58568d75effSDimitry Andric 
58681ad6265SDimitry Andric #if SANITIZER_APPLE
58768d75effSDimitry Andric TSAN_INTERCEPTOR(int, setjmp, void *env);
58868d75effSDimitry Andric TSAN_INTERCEPTOR(int, _setjmp, void *env);
58968d75effSDimitry Andric TSAN_INTERCEPTOR(int, sigsetjmp, void *env);
59081ad6265SDimitry Andric #else  // SANITIZER_APPLE
59168d75effSDimitry Andric 
59268d75effSDimitry Andric #if SANITIZER_NETBSD
59368d75effSDimitry Andric #define setjmp_symname __setjmp14
59468d75effSDimitry Andric #define sigsetjmp_symname __sigsetjmp14
59568d75effSDimitry Andric #else
59668d75effSDimitry Andric #define setjmp_symname setjmp
59768d75effSDimitry Andric #define sigsetjmp_symname sigsetjmp
59868d75effSDimitry Andric #endif
59968d75effSDimitry Andric 
60068d75effSDimitry Andric DEFINE_REAL(int, setjmp_symname, void *env)
60168d75effSDimitry Andric DEFINE_REAL(int, _setjmp, void *env)
60268d75effSDimitry Andric DEFINE_REAL(int, sigsetjmp_symname, void *env)
60368d75effSDimitry Andric #if !SANITIZER_NETBSD
60468d75effSDimitry Andric DEFINE_REAL(int, __sigsetjmp, void *env)
60568d75effSDimitry Andric #endif
60606c3fb27SDimitry Andric 
60706c3fb27SDimitry Andric // The real interceptor for setjmp is special, and implemented in pure asm. We
60806c3fb27SDimitry Andric // just need to initialize the REAL functions so that they can be used in asm.
60906c3fb27SDimitry Andric static void InitializeSetjmpInterceptors() {
61006c3fb27SDimitry Andric   // We can not use TSAN_INTERCEPT to get setjmp addr, because it does &setjmp and
61106c3fb27SDimitry Andric   // setjmp is not present in some versions of libc.
61206c3fb27SDimitry Andric   using __interception::InterceptFunction;
61306c3fb27SDimitry Andric   InterceptFunction(SANITIZER_STRINGIFY(setjmp_symname), (uptr*)&REAL(setjmp_symname), 0, 0);
61406c3fb27SDimitry Andric   InterceptFunction("_setjmp", (uptr*)&REAL(_setjmp), 0, 0);
61506c3fb27SDimitry Andric   InterceptFunction(SANITIZER_STRINGIFY(sigsetjmp_symname), (uptr*)&REAL(sigsetjmp_symname), 0,
61606c3fb27SDimitry Andric                     0);
61706c3fb27SDimitry Andric #if !SANITIZER_NETBSD
61806c3fb27SDimitry Andric   InterceptFunction("__sigsetjmp", (uptr*)&REAL(__sigsetjmp), 0, 0);
61906c3fb27SDimitry Andric #endif
62006c3fb27SDimitry Andric }
62181ad6265SDimitry Andric #endif  // SANITIZER_APPLE
62268d75effSDimitry Andric 
62368d75effSDimitry Andric #if SANITIZER_NETBSD
62468d75effSDimitry Andric #define longjmp_symname __longjmp14
62568d75effSDimitry Andric #define siglongjmp_symname __siglongjmp14
62668d75effSDimitry Andric #else
62768d75effSDimitry Andric #define longjmp_symname longjmp
62868d75effSDimitry Andric #define siglongjmp_symname siglongjmp
62968d75effSDimitry Andric #endif
63068d75effSDimitry Andric 
63168d75effSDimitry Andric TSAN_INTERCEPTOR(void, longjmp_symname, uptr *env, int val) {
63268d75effSDimitry Andric   // Note: if we call REAL(longjmp) in the context of ScopedInterceptor,
63368d75effSDimitry Andric   // bad things will happen. We will jump over ScopedInterceptor dtor and can
63468d75effSDimitry Andric   // leave thr->in_ignored_lib set.
63568d75effSDimitry Andric   {
63668d75effSDimitry Andric     SCOPED_INTERCEPTOR_RAW(longjmp_symname, env, val);
63768d75effSDimitry Andric   }
63868d75effSDimitry Andric   LongJmp(cur_thread(), env);
63968d75effSDimitry Andric   REAL(longjmp_symname)(env, val);
64068d75effSDimitry Andric }
64168d75effSDimitry Andric 
64268d75effSDimitry Andric TSAN_INTERCEPTOR(void, siglongjmp_symname, uptr *env, int val) {
64368d75effSDimitry Andric   {
64468d75effSDimitry Andric     SCOPED_INTERCEPTOR_RAW(siglongjmp_symname, env, val);
64568d75effSDimitry Andric   }
64668d75effSDimitry Andric   LongJmp(cur_thread(), env);
64768d75effSDimitry Andric   REAL(siglongjmp_symname)(env, val);
64868d75effSDimitry Andric }
64968d75effSDimitry Andric 
65068d75effSDimitry Andric #if SANITIZER_NETBSD
65168d75effSDimitry Andric TSAN_INTERCEPTOR(void, _longjmp, uptr *env, int val) {
65268d75effSDimitry Andric   {
65368d75effSDimitry Andric     SCOPED_INTERCEPTOR_RAW(_longjmp, env, val);
65468d75effSDimitry Andric   }
65568d75effSDimitry Andric   LongJmp(cur_thread(), env);
65668d75effSDimitry Andric   REAL(_longjmp)(env, val);
65768d75effSDimitry Andric }
65868d75effSDimitry Andric #endif
65968d75effSDimitry Andric 
66081ad6265SDimitry Andric #if !SANITIZER_APPLE
66168d75effSDimitry Andric TSAN_INTERCEPTOR(void*, malloc, uptr size) {
66268d75effSDimitry Andric   if (in_symbolizer())
66368d75effSDimitry Andric     return InternalAlloc(size);
66468d75effSDimitry Andric   void *p = 0;
66568d75effSDimitry Andric   {
66668d75effSDimitry Andric     SCOPED_INTERCEPTOR_RAW(malloc, size);
66768d75effSDimitry Andric     p = user_alloc(thr, pc, size);
66868d75effSDimitry Andric   }
66968d75effSDimitry Andric   invoke_malloc_hook(p, size);
67068d75effSDimitry Andric   return p;
67168d75effSDimitry Andric }
67268d75effSDimitry Andric 
673fe6060f1SDimitry Andric // In glibc<2.25, dynamic TLS blocks are allocated by __libc_memalign. Intercept
674fe6060f1SDimitry Andric // __libc_memalign so that (1) we can detect races (2) free will not be called
675fe6060f1SDimitry Andric // on libc internally allocated blocks.
67668d75effSDimitry Andric TSAN_INTERCEPTOR(void*, __libc_memalign, uptr align, uptr sz) {
677fe6060f1SDimitry Andric   SCOPED_INTERCEPTOR_RAW(__libc_memalign, align, sz);
67868d75effSDimitry Andric   return user_memalign(thr, pc, align, sz);
67968d75effSDimitry Andric }
68068d75effSDimitry Andric 
68168d75effSDimitry Andric TSAN_INTERCEPTOR(void*, calloc, uptr size, uptr n) {
68268d75effSDimitry Andric   if (in_symbolizer())
68368d75effSDimitry Andric     return InternalCalloc(size, n);
68468d75effSDimitry Andric   void *p = 0;
68568d75effSDimitry Andric   {
68668d75effSDimitry Andric     SCOPED_INTERCEPTOR_RAW(calloc, size, n);
68768d75effSDimitry Andric     p = user_calloc(thr, pc, size, n);
68868d75effSDimitry Andric   }
68968d75effSDimitry Andric   invoke_malloc_hook(p, n * size);
69068d75effSDimitry Andric   return p;
69168d75effSDimitry Andric }
69268d75effSDimitry Andric 
69368d75effSDimitry Andric TSAN_INTERCEPTOR(void*, realloc, void *p, uptr size) {
69468d75effSDimitry Andric   if (in_symbolizer())
69568d75effSDimitry Andric     return InternalRealloc(p, size);
69668d75effSDimitry Andric   if (p)
69768d75effSDimitry Andric     invoke_free_hook(p);
69868d75effSDimitry Andric   {
69968d75effSDimitry Andric     SCOPED_INTERCEPTOR_RAW(realloc, p, size);
70068d75effSDimitry Andric     p = user_realloc(thr, pc, p, size);
70168d75effSDimitry Andric   }
70268d75effSDimitry Andric   invoke_malloc_hook(p, size);
70368d75effSDimitry Andric   return p;
70468d75effSDimitry Andric }
70568d75effSDimitry Andric 
70668d75effSDimitry Andric TSAN_INTERCEPTOR(void*, reallocarray, void *p, uptr size, uptr n) {
70768d75effSDimitry Andric   if (in_symbolizer())
70868d75effSDimitry Andric     return InternalReallocArray(p, size, n);
70968d75effSDimitry Andric   if (p)
71068d75effSDimitry Andric     invoke_free_hook(p);
71168d75effSDimitry Andric   {
71268d75effSDimitry Andric     SCOPED_INTERCEPTOR_RAW(reallocarray, p, size, n);
71368d75effSDimitry Andric     p = user_reallocarray(thr, pc, p, size, n);
71468d75effSDimitry Andric   }
71568d75effSDimitry Andric   invoke_malloc_hook(p, size);
71668d75effSDimitry Andric   return p;
71768d75effSDimitry Andric }
71868d75effSDimitry Andric 
71968d75effSDimitry Andric TSAN_INTERCEPTOR(void, free, void *p) {
72068d75effSDimitry Andric   if (p == 0)
72168d75effSDimitry Andric     return;
72268d75effSDimitry Andric   if (in_symbolizer())
72368d75effSDimitry Andric     return InternalFree(p);
72468d75effSDimitry Andric   invoke_free_hook(p);
72568d75effSDimitry Andric   SCOPED_INTERCEPTOR_RAW(free, p);
72668d75effSDimitry Andric   user_free(thr, pc, p);
72768d75effSDimitry Andric }
72868d75effSDimitry Andric 
72968d75effSDimitry Andric TSAN_INTERCEPTOR(void, cfree, void *p) {
73068d75effSDimitry Andric   if (p == 0)
73168d75effSDimitry Andric     return;
73268d75effSDimitry Andric   if (in_symbolizer())
73368d75effSDimitry Andric     return InternalFree(p);
73468d75effSDimitry Andric   invoke_free_hook(p);
73568d75effSDimitry Andric   SCOPED_INTERCEPTOR_RAW(cfree, p);
73668d75effSDimitry Andric   user_free(thr, pc, p);
73768d75effSDimitry Andric }
73868d75effSDimitry Andric 
73968d75effSDimitry Andric TSAN_INTERCEPTOR(uptr, malloc_usable_size, void *p) {
74068d75effSDimitry Andric   SCOPED_INTERCEPTOR_RAW(malloc_usable_size, p);
74168d75effSDimitry Andric   return user_alloc_usable_size(p);
74268d75effSDimitry Andric }
74368d75effSDimitry Andric #endif
74468d75effSDimitry Andric 
74568d75effSDimitry Andric TSAN_INTERCEPTOR(char *, strcpy, char *dst, const char *src) {
74668d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(strcpy, dst, src);
74768d75effSDimitry Andric   uptr srclen = internal_strlen(src);
74868d75effSDimitry Andric   MemoryAccessRange(thr, pc, (uptr)dst, srclen + 1, true);
74968d75effSDimitry Andric   MemoryAccessRange(thr, pc, (uptr)src, srclen + 1, false);
75068d75effSDimitry Andric   return REAL(strcpy)(dst, src);
75168d75effSDimitry Andric }
75268d75effSDimitry Andric 
75368d75effSDimitry Andric TSAN_INTERCEPTOR(char*, strncpy, char *dst, char *src, uptr n) {
75468d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(strncpy, dst, src, n);
75568d75effSDimitry Andric   uptr srclen = internal_strnlen(src, n);
75668d75effSDimitry Andric   MemoryAccessRange(thr, pc, (uptr)dst, n, true);
75768d75effSDimitry Andric   MemoryAccessRange(thr, pc, (uptr)src, min(srclen + 1, n), false);
75868d75effSDimitry Andric   return REAL(strncpy)(dst, src, n);
75968d75effSDimitry Andric }
76068d75effSDimitry Andric 
76168d75effSDimitry Andric TSAN_INTERCEPTOR(char*, strdup, const char *str) {
76268d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(strdup, str);
76368d75effSDimitry Andric   // strdup will call malloc, so no instrumentation is required here.
76468d75effSDimitry Andric   return REAL(strdup)(str);
76568d75effSDimitry Andric }
76668d75effSDimitry Andric 
76768d75effSDimitry Andric // Zero out addr if it points into shadow memory and was provided as a hint
76868d75effSDimitry Andric // only, i.e., MAP_FIXED is not set.
76968d75effSDimitry Andric static bool fix_mmap_addr(void **addr, long_t sz, int flags) {
77068d75effSDimitry Andric   if (*addr) {
77168d75effSDimitry Andric     if (!IsAppMem((uptr)*addr) || !IsAppMem((uptr)*addr + sz - 1)) {
77268d75effSDimitry Andric       if (flags & MAP_FIXED) {
77368d75effSDimitry Andric         errno = errno_EINVAL;
77468d75effSDimitry Andric         return false;
77568d75effSDimitry Andric       } else {
77668d75effSDimitry Andric         *addr = 0;
77768d75effSDimitry Andric       }
77868d75effSDimitry Andric     }
77968d75effSDimitry Andric   }
78068d75effSDimitry Andric   return true;
78168d75effSDimitry Andric }
78268d75effSDimitry Andric 
78368d75effSDimitry Andric template <class Mmap>
78468d75effSDimitry Andric static void *mmap_interceptor(ThreadState *thr, uptr pc, Mmap real_mmap,
78568d75effSDimitry Andric                               void *addr, SIZE_T sz, int prot, int flags,
78668d75effSDimitry Andric                               int fd, OFF64_T off) {
78768d75effSDimitry Andric   if (!fix_mmap_addr(&addr, sz, flags)) return MAP_FAILED;
78868d75effSDimitry Andric   void *res = real_mmap(addr, sz, prot, flags, fd, off);
78968d75effSDimitry Andric   if (res != MAP_FAILED) {
790fe6060f1SDimitry Andric     if (!IsAppMem((uptr)res) || !IsAppMem((uptr)res + sz - 1)) {
791fe6060f1SDimitry Andric       Report("ThreadSanitizer: mmap at bad address: addr=%p size=%p res=%p\n",
792fe6060f1SDimitry Andric              addr, (void*)sz, res);
793fe6060f1SDimitry Andric       Die();
794fe6060f1SDimitry Andric     }
79568d75effSDimitry Andric     if (fd > 0) FdAccess(thr, pc, fd);
79668d75effSDimitry Andric     MemoryRangeImitateWriteOrResetRange(thr, pc, (uptr)res, sz);
79768d75effSDimitry Andric   }
79868d75effSDimitry Andric   return res;
79968d75effSDimitry Andric }
80068d75effSDimitry Andric 
80106c3fb27SDimitry Andric template <class Munmap>
80206c3fb27SDimitry Andric static int munmap_interceptor(ThreadState *thr, uptr pc, Munmap real_munmap,
80306c3fb27SDimitry Andric                                 void *addr, SIZE_T sz) {
80468d75effSDimitry Andric   UnmapShadow(thr, (uptr)addr, sz);
80506c3fb27SDimitry Andric   int res = real_munmap(addr, sz);
80668d75effSDimitry Andric   return res;
80768d75effSDimitry Andric }
80868d75effSDimitry Andric 
80968d75effSDimitry Andric #if SANITIZER_LINUX
81068d75effSDimitry Andric TSAN_INTERCEPTOR(void*, memalign, uptr align, uptr sz) {
81168d75effSDimitry Andric   SCOPED_INTERCEPTOR_RAW(memalign, align, sz);
81268d75effSDimitry Andric   return user_memalign(thr, pc, align, sz);
81368d75effSDimitry Andric }
81468d75effSDimitry Andric #define TSAN_MAYBE_INTERCEPT_MEMALIGN TSAN_INTERCEPT(memalign)
81568d75effSDimitry Andric #else
81668d75effSDimitry Andric #define TSAN_MAYBE_INTERCEPT_MEMALIGN
81768d75effSDimitry Andric #endif
81868d75effSDimitry Andric 
81981ad6265SDimitry Andric #if !SANITIZER_APPLE
82068d75effSDimitry Andric TSAN_INTERCEPTOR(void*, aligned_alloc, uptr align, uptr sz) {
82168d75effSDimitry Andric   if (in_symbolizer())
82268d75effSDimitry Andric     return InternalAlloc(sz, nullptr, align);
82368d75effSDimitry Andric   SCOPED_INTERCEPTOR_RAW(aligned_alloc, align, sz);
82468d75effSDimitry Andric   return user_aligned_alloc(thr, pc, align, sz);
82568d75effSDimitry Andric }
82668d75effSDimitry Andric 
82768d75effSDimitry Andric TSAN_INTERCEPTOR(void*, valloc, uptr sz) {
82868d75effSDimitry Andric   if (in_symbolizer())
82968d75effSDimitry Andric     return InternalAlloc(sz, nullptr, GetPageSizeCached());
83068d75effSDimitry Andric   SCOPED_INTERCEPTOR_RAW(valloc, sz);
83168d75effSDimitry Andric   return user_valloc(thr, pc, sz);
83268d75effSDimitry Andric }
83368d75effSDimitry Andric #endif
83468d75effSDimitry Andric 
83568d75effSDimitry Andric #if SANITIZER_LINUX
83668d75effSDimitry Andric TSAN_INTERCEPTOR(void*, pvalloc, uptr sz) {
83768d75effSDimitry Andric   if (in_symbolizer()) {
83868d75effSDimitry Andric     uptr PageSize = GetPageSizeCached();
83968d75effSDimitry Andric     sz = sz ? RoundUpTo(sz, PageSize) : PageSize;
84068d75effSDimitry Andric     return InternalAlloc(sz, nullptr, PageSize);
84168d75effSDimitry Andric   }
84268d75effSDimitry Andric   SCOPED_INTERCEPTOR_RAW(pvalloc, sz);
84368d75effSDimitry Andric   return user_pvalloc(thr, pc, sz);
84468d75effSDimitry Andric }
84568d75effSDimitry Andric #define TSAN_MAYBE_INTERCEPT_PVALLOC TSAN_INTERCEPT(pvalloc)
84668d75effSDimitry Andric #else
84768d75effSDimitry Andric #define TSAN_MAYBE_INTERCEPT_PVALLOC
84868d75effSDimitry Andric #endif
84968d75effSDimitry Andric 
85081ad6265SDimitry Andric #if !SANITIZER_APPLE
85168d75effSDimitry Andric TSAN_INTERCEPTOR(int, posix_memalign, void **memptr, uptr align, uptr sz) {
85268d75effSDimitry Andric   if (in_symbolizer()) {
85368d75effSDimitry Andric     void *p = InternalAlloc(sz, nullptr, align);
85468d75effSDimitry Andric     if (!p)
85568d75effSDimitry Andric       return errno_ENOMEM;
85668d75effSDimitry Andric     *memptr = p;
85768d75effSDimitry Andric     return 0;
85868d75effSDimitry Andric   }
85968d75effSDimitry Andric   SCOPED_INTERCEPTOR_RAW(posix_memalign, memptr, align, sz);
86068d75effSDimitry Andric   return user_posix_memalign(thr, pc, memptr, align, sz);
86168d75effSDimitry Andric }
86268d75effSDimitry Andric #endif
86368d75effSDimitry Andric 
864349cc55cSDimitry Andric // Both __cxa_guard_acquire and pthread_once 0-initialize
865349cc55cSDimitry Andric // the object initially. pthread_once does not have any
866349cc55cSDimitry Andric // other ABI requirements. __cxa_guard_acquire assumes
867349cc55cSDimitry Andric // that any non-0 value in the first byte means that
868349cc55cSDimitry Andric // initialization is completed. Contents of the remaining
869349cc55cSDimitry Andric // bytes are up to us.
870349cc55cSDimitry Andric constexpr u32 kGuardInit = 0;
871349cc55cSDimitry Andric constexpr u32 kGuardDone = 1;
872349cc55cSDimitry Andric constexpr u32 kGuardRunning = 1 << 16;
873349cc55cSDimitry Andric constexpr u32 kGuardWaiter = 1 << 17;
874349cc55cSDimitry Andric 
875349cc55cSDimitry Andric static int guard_acquire(ThreadState *thr, uptr pc, atomic_uint32_t *g,
876349cc55cSDimitry Andric                          bool blocking_hooks = true) {
877349cc55cSDimitry Andric   if (blocking_hooks)
878349cc55cSDimitry Andric     OnPotentiallyBlockingRegionBegin();
879349cc55cSDimitry Andric   auto on_exit = at_scope_exit([blocking_hooks] {
880349cc55cSDimitry Andric     if (blocking_hooks)
881349cc55cSDimitry Andric       OnPotentiallyBlockingRegionEnd();
882349cc55cSDimitry Andric   });
883349cc55cSDimitry Andric 
884349cc55cSDimitry Andric   for (;;) {
885349cc55cSDimitry Andric     u32 cmp = atomic_load(g, memory_order_acquire);
886349cc55cSDimitry Andric     if (cmp == kGuardInit) {
887349cc55cSDimitry Andric       if (atomic_compare_exchange_strong(g, &cmp, kGuardRunning,
888349cc55cSDimitry Andric                                          memory_order_relaxed))
889349cc55cSDimitry Andric         return 1;
890349cc55cSDimitry Andric     } else if (cmp == kGuardDone) {
891349cc55cSDimitry Andric       if (!thr->in_ignored_lib)
892349cc55cSDimitry Andric         Acquire(thr, pc, (uptr)g);
893349cc55cSDimitry Andric       return 0;
894349cc55cSDimitry Andric     } else {
895349cc55cSDimitry Andric       if ((cmp & kGuardWaiter) ||
896349cc55cSDimitry Andric           atomic_compare_exchange_strong(g, &cmp, cmp | kGuardWaiter,
897349cc55cSDimitry Andric                                          memory_order_relaxed))
898349cc55cSDimitry Andric         FutexWait(g, cmp | kGuardWaiter);
899349cc55cSDimitry Andric     }
900349cc55cSDimitry Andric   }
901349cc55cSDimitry Andric }
902349cc55cSDimitry Andric 
903349cc55cSDimitry Andric static void guard_release(ThreadState *thr, uptr pc, atomic_uint32_t *g,
904349cc55cSDimitry Andric                           u32 v) {
905349cc55cSDimitry Andric   if (!thr->in_ignored_lib)
906349cc55cSDimitry Andric     Release(thr, pc, (uptr)g);
907349cc55cSDimitry Andric   u32 old = atomic_exchange(g, v, memory_order_release);
908349cc55cSDimitry Andric   if (old & kGuardWaiter)
909349cc55cSDimitry Andric     FutexWake(g, 1 << 30);
910349cc55cSDimitry Andric }
911349cc55cSDimitry Andric 
91268d75effSDimitry Andric // __cxa_guard_acquire and friends need to be intercepted in a special way -
91368d75effSDimitry Andric // regular interceptors will break statically-linked libstdc++. Linux
91468d75effSDimitry Andric // interceptors are especially defined as weak functions (so that they don't
91568d75effSDimitry Andric // cause link errors when user defines them as well). So they silently
91668d75effSDimitry Andric // auto-disable themselves when such symbol is already present in the binary. If
91768d75effSDimitry Andric // we link libstdc++ statically, it will bring own __cxa_guard_acquire which
91868d75effSDimitry Andric // will silently replace our interceptor.  That's why on Linux we simply export
91968d75effSDimitry Andric // these interceptors with INTERFACE_ATTRIBUTE.
92068d75effSDimitry Andric // On OS X, we don't support statically linking, so we just use a regular
92168d75effSDimitry Andric // interceptor.
92281ad6265SDimitry Andric #if SANITIZER_APPLE
92368d75effSDimitry Andric #define STDCXX_INTERCEPTOR TSAN_INTERCEPTOR
92468d75effSDimitry Andric #else
92568d75effSDimitry Andric #define STDCXX_INTERCEPTOR(rettype, name, ...) \
92668d75effSDimitry Andric   extern "C" rettype INTERFACE_ATTRIBUTE name(__VA_ARGS__)
92768d75effSDimitry Andric #endif
92868d75effSDimitry Andric 
92968d75effSDimitry Andric // Used in thread-safe function static initialization.
93068d75effSDimitry Andric STDCXX_INTERCEPTOR(int, __cxa_guard_acquire, atomic_uint32_t *g) {
93168d75effSDimitry Andric   SCOPED_INTERCEPTOR_RAW(__cxa_guard_acquire, g);
932349cc55cSDimitry Andric   return guard_acquire(thr, pc, g);
93368d75effSDimitry Andric }
93468d75effSDimitry Andric 
93568d75effSDimitry Andric STDCXX_INTERCEPTOR(void, __cxa_guard_release, atomic_uint32_t *g) {
93668d75effSDimitry Andric   SCOPED_INTERCEPTOR_RAW(__cxa_guard_release, g);
937349cc55cSDimitry Andric   guard_release(thr, pc, g, kGuardDone);
93868d75effSDimitry Andric }
93968d75effSDimitry Andric 
94068d75effSDimitry Andric STDCXX_INTERCEPTOR(void, __cxa_guard_abort, atomic_uint32_t *g) {
94168d75effSDimitry Andric   SCOPED_INTERCEPTOR_RAW(__cxa_guard_abort, g);
942349cc55cSDimitry Andric   guard_release(thr, pc, g, kGuardInit);
94368d75effSDimitry Andric }
94468d75effSDimitry Andric 
94568d75effSDimitry Andric namespace __tsan {
94668d75effSDimitry Andric void DestroyThreadState() {
94768d75effSDimitry Andric   ThreadState *thr = cur_thread();
94868d75effSDimitry Andric   Processor *proc = thr->proc();
94968d75effSDimitry Andric   ThreadFinish(thr);
95068d75effSDimitry Andric   ProcUnwire(proc, thr);
95168d75effSDimitry Andric   ProcDestroy(proc);
9525ffd83dbSDimitry Andric   DTLS_Destroy();
9535ffd83dbSDimitry Andric   cur_thread_finalize();
9545ffd83dbSDimitry Andric }
9555ffd83dbSDimitry Andric 
9565ffd83dbSDimitry Andric void PlatformCleanUpThreadState(ThreadState *thr) {
957bdd1243dSDimitry Andric   ThreadSignalContext *sctx = (ThreadSignalContext *)atomic_load(
958bdd1243dSDimitry Andric       &thr->signal_ctx, memory_order_relaxed);
95968d75effSDimitry Andric   if (sctx) {
960bdd1243dSDimitry Andric     atomic_store(&thr->signal_ctx, 0, memory_order_relaxed);
96168d75effSDimitry Andric     UnmapOrDie(sctx, sizeof(*sctx));
96268d75effSDimitry Andric   }
96368d75effSDimitry Andric }
96468d75effSDimitry Andric }  // namespace __tsan
96568d75effSDimitry Andric 
96681ad6265SDimitry Andric #if !SANITIZER_APPLE && !SANITIZER_NETBSD && !SANITIZER_FREEBSD
96768d75effSDimitry Andric static void thread_finalize(void *v) {
96868d75effSDimitry Andric   uptr iter = (uptr)v;
96968d75effSDimitry Andric   if (iter > 1) {
97068d75effSDimitry Andric     if (pthread_setspecific(interceptor_ctx()->finalize_key,
97168d75effSDimitry Andric         (void*)(iter - 1))) {
97268d75effSDimitry Andric       Printf("ThreadSanitizer: failed to set thread key\n");
97368d75effSDimitry Andric       Die();
97468d75effSDimitry Andric     }
97568d75effSDimitry Andric     return;
97668d75effSDimitry Andric   }
97768d75effSDimitry Andric   DestroyThreadState();
97868d75effSDimitry Andric }
97968d75effSDimitry Andric #endif
98068d75effSDimitry Andric 
98168d75effSDimitry Andric 
98268d75effSDimitry Andric struct ThreadParam {
98368d75effSDimitry Andric   void* (*callback)(void *arg);
98468d75effSDimitry Andric   void *param;
985349cc55cSDimitry Andric   Tid tid;
986349cc55cSDimitry Andric   Semaphore created;
987349cc55cSDimitry Andric   Semaphore started;
98868d75effSDimitry Andric };
98968d75effSDimitry Andric 
99068d75effSDimitry Andric extern "C" void *__tsan_thread_start_func(void *arg) {
99168d75effSDimitry Andric   ThreadParam *p = (ThreadParam*)arg;
99268d75effSDimitry Andric   void* (*callback)(void *arg) = p->callback;
99368d75effSDimitry Andric   void *param = p->param;
99468d75effSDimitry Andric   {
995349cc55cSDimitry Andric     ThreadState *thr = cur_thread_init();
99668d75effSDimitry Andric     // Thread-local state is not initialized yet.
99768d75effSDimitry Andric     ScopedIgnoreInterceptors ignore;
99881ad6265SDimitry Andric #if !SANITIZER_APPLE && !SANITIZER_NETBSD && !SANITIZER_FREEBSD
99968d75effSDimitry Andric     ThreadIgnoreBegin(thr, 0);
100068d75effSDimitry Andric     if (pthread_setspecific(interceptor_ctx()->finalize_key,
100168d75effSDimitry Andric                             (void *)GetPthreadDestructorIterations())) {
100268d75effSDimitry Andric       Printf("ThreadSanitizer: failed to set thread key\n");
100368d75effSDimitry Andric       Die();
100468d75effSDimitry Andric     }
1005349cc55cSDimitry Andric     ThreadIgnoreEnd(thr);
100668d75effSDimitry Andric #endif
1007349cc55cSDimitry Andric     p->created.Wait();
100868d75effSDimitry Andric     Processor *proc = ProcCreate();
100968d75effSDimitry Andric     ProcWire(proc, thr);
1010349cc55cSDimitry Andric     ThreadStart(thr, p->tid, GetTid(), ThreadType::Regular);
1011349cc55cSDimitry Andric     p->started.Post();
101268d75effSDimitry Andric   }
101368d75effSDimitry Andric   void *res = callback(param);
101468d75effSDimitry Andric   // Prevent the callback from being tail called,
101568d75effSDimitry Andric   // it mixes up stack traces.
101668d75effSDimitry Andric   volatile int foo = 42;
101768d75effSDimitry Andric   foo++;
101868d75effSDimitry Andric   return res;
101968d75effSDimitry Andric }
102068d75effSDimitry Andric 
102168d75effSDimitry Andric TSAN_INTERCEPTOR(int, pthread_create,
102268d75effSDimitry Andric     void *th, void *attr, void *(*callback)(void*), void * param) {
102368d75effSDimitry Andric   SCOPED_INTERCEPTOR_RAW(pthread_create, th, attr, callback, param);
102468d75effSDimitry Andric 
102568d75effSDimitry Andric   MaybeSpawnBackgroundThread();
102668d75effSDimitry Andric 
102768d75effSDimitry Andric   if (ctx->after_multithreaded_fork) {
102868d75effSDimitry Andric     if (flags()->die_after_fork) {
102968d75effSDimitry Andric       Report("ThreadSanitizer: starting new threads after multi-threaded "
103068d75effSDimitry Andric           "fork is not supported. Dying (set die_after_fork=0 to override)\n");
103168d75effSDimitry Andric       Die();
103268d75effSDimitry Andric     } else {
1033349cc55cSDimitry Andric       VPrintf(1,
1034349cc55cSDimitry Andric               "ThreadSanitizer: starting new threads after multi-threaded "
1035349cc55cSDimitry Andric               "fork is not supported (pid %lu). Continuing because of "
1036349cc55cSDimitry Andric               "die_after_fork=0, but you are on your own\n",
1037349cc55cSDimitry Andric               internal_getpid());
103868d75effSDimitry Andric     }
103968d75effSDimitry Andric   }
104068d75effSDimitry Andric   __sanitizer_pthread_attr_t myattr;
104168d75effSDimitry Andric   if (attr == 0) {
104268d75effSDimitry Andric     pthread_attr_init(&myattr);
104368d75effSDimitry Andric     attr = &myattr;
104468d75effSDimitry Andric   }
104568d75effSDimitry Andric   int detached = 0;
104668d75effSDimitry Andric   REAL(pthread_attr_getdetachstate)(attr, &detached);
104768d75effSDimitry Andric   AdjustStackSize(attr);
104868d75effSDimitry Andric 
104968d75effSDimitry Andric   ThreadParam p;
105068d75effSDimitry Andric   p.callback = callback;
105168d75effSDimitry Andric   p.param = param;
1052349cc55cSDimitry Andric   p.tid = kMainTid;
105368d75effSDimitry Andric   int res = -1;
105468d75effSDimitry Andric   {
105568d75effSDimitry Andric     // Otherwise we see false positives in pthread stack manipulation.
105668d75effSDimitry Andric     ScopedIgnoreInterceptors ignore;
105768d75effSDimitry Andric     ThreadIgnoreBegin(thr, pc);
105868d75effSDimitry Andric     res = REAL(pthread_create)(th, attr, __tsan_thread_start_func, &p);
1059349cc55cSDimitry Andric     ThreadIgnoreEnd(thr);
106068d75effSDimitry Andric   }
106168d75effSDimitry Andric   if (res == 0) {
1062349cc55cSDimitry Andric     p.tid = ThreadCreate(thr, pc, *(uptr *)th, IsStateDetached(detached));
1063349cc55cSDimitry Andric     CHECK_NE(p.tid, kMainTid);
106468d75effSDimitry Andric     // Synchronization on p.tid serves two purposes:
106568d75effSDimitry Andric     // 1. ThreadCreate must finish before the new thread starts.
106668d75effSDimitry Andric     //    Otherwise the new thread can call pthread_detach, but the pthread_t
106768d75effSDimitry Andric     //    identifier is not yet registered in ThreadRegistry by ThreadCreate.
106868d75effSDimitry Andric     // 2. ThreadStart must finish before this thread continues.
106968d75effSDimitry Andric     //    Otherwise, this thread can call pthread_detach and reset thr->sync
107068d75effSDimitry Andric     //    before the new thread got a chance to acquire from it in ThreadStart.
1071349cc55cSDimitry Andric     p.created.Post();
1072349cc55cSDimitry Andric     p.started.Wait();
107368d75effSDimitry Andric   }
107468d75effSDimitry Andric   if (attr == &myattr)
107568d75effSDimitry Andric     pthread_attr_destroy(&myattr);
107668d75effSDimitry Andric   return res;
107768d75effSDimitry Andric }
107868d75effSDimitry Andric 
107968d75effSDimitry Andric TSAN_INTERCEPTOR(int, pthread_join, void *th, void **ret) {
108068d75effSDimitry Andric   SCOPED_INTERCEPTOR_RAW(pthread_join, th, ret);
1081349cc55cSDimitry Andric   Tid tid = ThreadConsumeTid(thr, pc, (uptr)th);
108268d75effSDimitry Andric   ThreadIgnoreBegin(thr, pc);
108368d75effSDimitry Andric   int res = BLOCK_REAL(pthread_join)(th, ret);
1084349cc55cSDimitry Andric   ThreadIgnoreEnd(thr);
108568d75effSDimitry Andric   if (res == 0) {
108668d75effSDimitry Andric     ThreadJoin(thr, pc, tid);
108768d75effSDimitry Andric   }
108868d75effSDimitry Andric   return res;
108968d75effSDimitry Andric }
109068d75effSDimitry Andric 
1091*0fca6ea1SDimitry Andric // DEFINE_INTERNAL_PTHREAD_FUNCTIONS
1092*0fca6ea1SDimitry Andric namespace __sanitizer {
1093*0fca6ea1SDimitry Andric int internal_pthread_create(void *th, void *attr, void *(*callback)(void *),
1094*0fca6ea1SDimitry Andric                             void *param) {
1095*0fca6ea1SDimitry Andric   ScopedIgnoreInterceptors ignore;
1096*0fca6ea1SDimitry Andric   return REAL(pthread_create)(th, attr, callback, param);
1097*0fca6ea1SDimitry Andric }
1098*0fca6ea1SDimitry Andric int internal_pthread_join(void *th, void **ret) {
1099*0fca6ea1SDimitry Andric   ScopedIgnoreInterceptors ignore;
1100*0fca6ea1SDimitry Andric   return REAL(pthread_join(th, ret));
1101*0fca6ea1SDimitry Andric }
1102*0fca6ea1SDimitry Andric }  // namespace __sanitizer
110368d75effSDimitry Andric 
110468d75effSDimitry Andric TSAN_INTERCEPTOR(int, pthread_detach, void *th) {
11055ffd83dbSDimitry Andric   SCOPED_INTERCEPTOR_RAW(pthread_detach, th);
1106349cc55cSDimitry Andric   Tid tid = ThreadConsumeTid(thr, pc, (uptr)th);
110768d75effSDimitry Andric   int res = REAL(pthread_detach)(th);
110868d75effSDimitry Andric   if (res == 0) {
110968d75effSDimitry Andric     ThreadDetach(thr, pc, tid);
111068d75effSDimitry Andric   }
111168d75effSDimitry Andric   return res;
111268d75effSDimitry Andric }
111368d75effSDimitry Andric 
111468d75effSDimitry Andric TSAN_INTERCEPTOR(void, pthread_exit, void *retval) {
111568d75effSDimitry Andric   {
111668d75effSDimitry Andric     SCOPED_INTERCEPTOR_RAW(pthread_exit, retval);
111781ad6265SDimitry Andric #if !SANITIZER_APPLE && !SANITIZER_ANDROID
111868d75effSDimitry Andric     CHECK_EQ(thr, &cur_thread_placeholder);
111968d75effSDimitry Andric #endif
112068d75effSDimitry Andric   }
112168d75effSDimitry Andric   REAL(pthread_exit)(retval);
112268d75effSDimitry Andric }
112368d75effSDimitry Andric 
112468d75effSDimitry Andric #if SANITIZER_LINUX
112568d75effSDimitry Andric TSAN_INTERCEPTOR(int, pthread_tryjoin_np, void *th, void **ret) {
11265ffd83dbSDimitry Andric   SCOPED_INTERCEPTOR_RAW(pthread_tryjoin_np, th, ret);
1127349cc55cSDimitry Andric   Tid tid = ThreadConsumeTid(thr, pc, (uptr)th);
112868d75effSDimitry Andric   ThreadIgnoreBegin(thr, pc);
112968d75effSDimitry Andric   int res = REAL(pthread_tryjoin_np)(th, ret);
1130349cc55cSDimitry Andric   ThreadIgnoreEnd(thr);
113168d75effSDimitry Andric   if (res == 0)
113268d75effSDimitry Andric     ThreadJoin(thr, pc, tid);
113368d75effSDimitry Andric   else
113468d75effSDimitry Andric     ThreadNotJoined(thr, pc, tid, (uptr)th);
113568d75effSDimitry Andric   return res;
113668d75effSDimitry Andric }
113768d75effSDimitry Andric 
113868d75effSDimitry Andric TSAN_INTERCEPTOR(int, pthread_timedjoin_np, void *th, void **ret,
113968d75effSDimitry Andric                  const struct timespec *abstime) {
11405ffd83dbSDimitry Andric   SCOPED_INTERCEPTOR_RAW(pthread_timedjoin_np, th, ret, abstime);
1141349cc55cSDimitry Andric   Tid tid = ThreadConsumeTid(thr, pc, (uptr)th);
114268d75effSDimitry Andric   ThreadIgnoreBegin(thr, pc);
114368d75effSDimitry Andric   int res = BLOCK_REAL(pthread_timedjoin_np)(th, ret, abstime);
1144349cc55cSDimitry Andric   ThreadIgnoreEnd(thr);
114568d75effSDimitry Andric   if (res == 0)
114668d75effSDimitry Andric     ThreadJoin(thr, pc, tid);
114768d75effSDimitry Andric   else
114868d75effSDimitry Andric     ThreadNotJoined(thr, pc, tid, (uptr)th);
114968d75effSDimitry Andric   return res;
115068d75effSDimitry Andric }
115168d75effSDimitry Andric #endif
115268d75effSDimitry Andric 
115368d75effSDimitry Andric // Problem:
115468d75effSDimitry Andric // NPTL implementation of pthread_cond has 2 versions (2.2.5 and 2.3.2).
115568d75effSDimitry Andric // pthread_cond_t has different size in the different versions.
115668d75effSDimitry Andric // If call new REAL functions for old pthread_cond_t, they will corrupt memory
115768d75effSDimitry Andric // after pthread_cond_t (old cond is smaller).
115868d75effSDimitry Andric // If we call old REAL functions for new pthread_cond_t, we will lose  some
115968d75effSDimitry Andric // functionality (e.g. old functions do not support waiting against
116068d75effSDimitry Andric // CLOCK_REALTIME).
116168d75effSDimitry Andric // Proper handling would require to have 2 versions of interceptors as well.
116268d75effSDimitry Andric // But this is messy, in particular requires linker scripts when sanitizer
116368d75effSDimitry Andric // runtime is linked into a shared library.
116468d75effSDimitry Andric // Instead we assume we don't have dynamic libraries built against old
116568d75effSDimitry Andric // pthread (2.2.5 is dated by 2002). And provide legacy_pthread_cond flag
116668d75effSDimitry Andric // that allows to work with old libraries (but this mode does not support
116768d75effSDimitry Andric // some features, e.g. pthread_condattr_getpshared).
116868d75effSDimitry Andric static void *init_cond(void *c, bool force = false) {
116968d75effSDimitry Andric   // sizeof(pthread_cond_t) >= sizeof(uptr) in both versions.
117068d75effSDimitry Andric   // So we allocate additional memory on the side large enough to hold
117168d75effSDimitry Andric   // any pthread_cond_t object. Always call new REAL functions, but pass
117268d75effSDimitry Andric   // the aux object to them.
117368d75effSDimitry Andric   // Note: the code assumes that PTHREAD_COND_INITIALIZER initializes
117468d75effSDimitry Andric   // first word of pthread_cond_t to zero.
117568d75effSDimitry Andric   // It's all relevant only for linux.
117668d75effSDimitry Andric   if (!common_flags()->legacy_pthread_cond)
117768d75effSDimitry Andric     return c;
117868d75effSDimitry Andric   atomic_uintptr_t *p = (atomic_uintptr_t*)c;
117968d75effSDimitry Andric   uptr cond = atomic_load(p, memory_order_acquire);
118068d75effSDimitry Andric   if (!force && cond != 0)
118168d75effSDimitry Andric     return (void*)cond;
118268d75effSDimitry Andric   void *newcond = WRAP(malloc)(pthread_cond_t_sz);
118368d75effSDimitry Andric   internal_memset(newcond, 0, pthread_cond_t_sz);
118468d75effSDimitry Andric   if (atomic_compare_exchange_strong(p, &cond, (uptr)newcond,
118568d75effSDimitry Andric       memory_order_acq_rel))
118668d75effSDimitry Andric     return newcond;
118768d75effSDimitry Andric   WRAP(free)(newcond);
118868d75effSDimitry Andric   return (void*)cond;
118968d75effSDimitry Andric }
119068d75effSDimitry Andric 
1191e8d8bef9SDimitry Andric namespace {
1192e8d8bef9SDimitry Andric 
1193e8d8bef9SDimitry Andric template <class Fn>
119468d75effSDimitry Andric struct CondMutexUnlockCtx {
119568d75effSDimitry Andric   ScopedInterceptor *si;
119668d75effSDimitry Andric   ThreadState *thr;
119768d75effSDimitry Andric   uptr pc;
119868d75effSDimitry Andric   void *m;
1199e8d8bef9SDimitry Andric   void *c;
1200e8d8bef9SDimitry Andric   const Fn &fn;
1201e8d8bef9SDimitry Andric 
1202e8d8bef9SDimitry Andric   int Cancel() const { return fn(); }
1203e8d8bef9SDimitry Andric   void Unlock() const;
120468d75effSDimitry Andric };
120568d75effSDimitry Andric 
1206e8d8bef9SDimitry Andric template <class Fn>
1207e8d8bef9SDimitry Andric void CondMutexUnlockCtx<Fn>::Unlock() const {
120868d75effSDimitry Andric   // pthread_cond_wait interceptor has enabled async signal delivery
120968d75effSDimitry Andric   // (see BlockingCall below). Disable async signals since we are running
121068d75effSDimitry Andric   // tsan code. Also ScopedInterceptor and BlockingCall destructors won't run
121168d75effSDimitry Andric   // since the thread is cancelled, so we have to manually execute them
121268d75effSDimitry Andric   // (the thread still can run some user code due to pthread_cleanup_push).
1213bdd1243dSDimitry Andric   CHECK_EQ(atomic_load(&thr->in_blocking_func, memory_order_relaxed), 1);
1214bdd1243dSDimitry Andric   atomic_store(&thr->in_blocking_func, 0, memory_order_relaxed);
1215e8d8bef9SDimitry Andric   MutexPostLock(thr, pc, (uptr)m, MutexFlagDoPreLockOnPostLock);
121668d75effSDimitry Andric   // Undo BlockingCall ctor effects.
1217e8d8bef9SDimitry Andric   thr->ignore_interceptors--;
1218e8d8bef9SDimitry Andric   si->~ScopedInterceptor();
121968d75effSDimitry Andric }
1220e8d8bef9SDimitry Andric }  // namespace
122168d75effSDimitry Andric 
122268d75effSDimitry Andric INTERCEPTOR(int, pthread_cond_init, void *c, void *a) {
122368d75effSDimitry Andric   void *cond = init_cond(c, true);
122468d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(pthread_cond_init, cond, a);
122568d75effSDimitry Andric   MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), true);
122668d75effSDimitry Andric   return REAL(pthread_cond_init)(cond, a);
122768d75effSDimitry Andric }
122868d75effSDimitry Andric 
1229e8d8bef9SDimitry Andric template <class Fn>
1230e8d8bef9SDimitry Andric int cond_wait(ThreadState *thr, uptr pc, ScopedInterceptor *si, const Fn &fn,
1231e8d8bef9SDimitry Andric               void *c, void *m) {
123268d75effSDimitry Andric   MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), false);
123368d75effSDimitry Andric   MutexUnlock(thr, pc, (uptr)m);
123468d75effSDimitry Andric   int res = 0;
123568d75effSDimitry Andric   // This ensures that we handle mutex lock even in case of pthread_cancel.
123668d75effSDimitry Andric   // See test/tsan/cond_cancel.cpp.
123768d75effSDimitry Andric   {
123868d75effSDimitry Andric     // Enable signal delivery while the thread is blocked.
123968d75effSDimitry Andric     BlockingCall bc(thr);
1240e8d8bef9SDimitry Andric     CondMutexUnlockCtx<Fn> arg = {si, thr, pc, m, c, fn};
124168d75effSDimitry Andric     res = call_pthread_cancel_with_cleanup(
1242e8d8bef9SDimitry Andric         [](void *arg) -> int {
1243e8d8bef9SDimitry Andric           return ((const CondMutexUnlockCtx<Fn> *)arg)->Cancel();
1244e8d8bef9SDimitry Andric         },
1245e8d8bef9SDimitry Andric         [](void *arg) { ((const CondMutexUnlockCtx<Fn> *)arg)->Unlock(); },
1246e8d8bef9SDimitry Andric         &arg);
124768d75effSDimitry Andric   }
124868d75effSDimitry Andric   if (res == errno_EOWNERDEAD) MutexRepair(thr, pc, (uptr)m);
124968d75effSDimitry Andric   MutexPostLock(thr, pc, (uptr)m, MutexFlagDoPreLockOnPostLock);
125068d75effSDimitry Andric   return res;
125168d75effSDimitry Andric }
125268d75effSDimitry Andric 
125368d75effSDimitry Andric INTERCEPTOR(int, pthread_cond_wait, void *c, void *m) {
125468d75effSDimitry Andric   void *cond = init_cond(c);
125568d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(pthread_cond_wait, cond, m);
1256e8d8bef9SDimitry Andric   return cond_wait(
1257e8d8bef9SDimitry Andric       thr, pc, &si, [=]() { return REAL(pthread_cond_wait)(cond, m); }, cond,
1258e8d8bef9SDimitry Andric       m);
125968d75effSDimitry Andric }
126068d75effSDimitry Andric 
126168d75effSDimitry Andric INTERCEPTOR(int, pthread_cond_timedwait, void *c, void *m, void *abstime) {
126268d75effSDimitry Andric   void *cond = init_cond(c);
126368d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(pthread_cond_timedwait, cond, m, abstime);
1264e8d8bef9SDimitry Andric   return cond_wait(
1265e8d8bef9SDimitry Andric       thr, pc, &si,
1266e8d8bef9SDimitry Andric       [=]() { return REAL(pthread_cond_timedwait)(cond, m, abstime); }, cond,
1267e8d8bef9SDimitry Andric       m);
126868d75effSDimitry Andric }
126968d75effSDimitry Andric 
1270e8d8bef9SDimitry Andric #if SANITIZER_LINUX
1271e8d8bef9SDimitry Andric INTERCEPTOR(int, pthread_cond_clockwait, void *c, void *m,
1272e8d8bef9SDimitry Andric             __sanitizer_clockid_t clock, void *abstime) {
1273e8d8bef9SDimitry Andric   void *cond = init_cond(c);
1274e8d8bef9SDimitry Andric   SCOPED_TSAN_INTERCEPTOR(pthread_cond_clockwait, cond, m, clock, abstime);
1275e8d8bef9SDimitry Andric   return cond_wait(
1276e8d8bef9SDimitry Andric       thr, pc, &si,
1277e8d8bef9SDimitry Andric       [=]() { return REAL(pthread_cond_clockwait)(cond, m, clock, abstime); },
1278e8d8bef9SDimitry Andric       cond, m);
1279e8d8bef9SDimitry Andric }
1280e8d8bef9SDimitry Andric #define TSAN_MAYBE_PTHREAD_COND_CLOCKWAIT TSAN_INTERCEPT(pthread_cond_clockwait)
1281e8d8bef9SDimitry Andric #else
1282e8d8bef9SDimitry Andric #define TSAN_MAYBE_PTHREAD_COND_CLOCKWAIT
1283e8d8bef9SDimitry Andric #endif
1284e8d8bef9SDimitry Andric 
128581ad6265SDimitry Andric #if SANITIZER_APPLE
128668d75effSDimitry Andric INTERCEPTOR(int, pthread_cond_timedwait_relative_np, void *c, void *m,
128768d75effSDimitry Andric             void *reltime) {
128868d75effSDimitry Andric   void *cond = init_cond(c);
128968d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(pthread_cond_timedwait_relative_np, cond, m, reltime);
1290e8d8bef9SDimitry Andric   return cond_wait(
1291e8d8bef9SDimitry Andric       thr, pc, &si,
1292e8d8bef9SDimitry Andric       [=]() {
1293e8d8bef9SDimitry Andric         return REAL(pthread_cond_timedwait_relative_np)(cond, m, reltime);
1294e8d8bef9SDimitry Andric       },
1295e8d8bef9SDimitry Andric       cond, m);
129668d75effSDimitry Andric }
129768d75effSDimitry Andric #endif
129868d75effSDimitry Andric 
129968d75effSDimitry Andric INTERCEPTOR(int, pthread_cond_signal, void *c) {
130068d75effSDimitry Andric   void *cond = init_cond(c);
130168d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(pthread_cond_signal, cond);
130268d75effSDimitry Andric   MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), false);
130368d75effSDimitry Andric   return REAL(pthread_cond_signal)(cond);
130468d75effSDimitry Andric }
130568d75effSDimitry Andric 
130668d75effSDimitry Andric INTERCEPTOR(int, pthread_cond_broadcast, void *c) {
130768d75effSDimitry Andric   void *cond = init_cond(c);
130868d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(pthread_cond_broadcast, cond);
130968d75effSDimitry Andric   MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), false);
131068d75effSDimitry Andric   return REAL(pthread_cond_broadcast)(cond);
131168d75effSDimitry Andric }
131268d75effSDimitry Andric 
131368d75effSDimitry Andric INTERCEPTOR(int, pthread_cond_destroy, void *c) {
131468d75effSDimitry Andric   void *cond = init_cond(c);
131568d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(pthread_cond_destroy, cond);
131668d75effSDimitry Andric   MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), true);
131768d75effSDimitry Andric   int res = REAL(pthread_cond_destroy)(cond);
131868d75effSDimitry Andric   if (common_flags()->legacy_pthread_cond) {
131968d75effSDimitry Andric     // Free our aux cond and zero the pointer to not leave dangling pointers.
132068d75effSDimitry Andric     WRAP(free)(cond);
132168d75effSDimitry Andric     atomic_store((atomic_uintptr_t*)c, 0, memory_order_relaxed);
132268d75effSDimitry Andric   }
132368d75effSDimitry Andric   return res;
132468d75effSDimitry Andric }
132568d75effSDimitry Andric 
132668d75effSDimitry Andric TSAN_INTERCEPTOR(int, pthread_mutex_init, void *m, void *a) {
132768d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(pthread_mutex_init, m, a);
132868d75effSDimitry Andric   int res = REAL(pthread_mutex_init)(m, a);
132968d75effSDimitry Andric   if (res == 0) {
133068d75effSDimitry Andric     u32 flagz = 0;
133168d75effSDimitry Andric     if (a) {
133268d75effSDimitry Andric       int type = 0;
133368d75effSDimitry Andric       if (REAL(pthread_mutexattr_gettype)(a, &type) == 0)
133468d75effSDimitry Andric         if (type == PTHREAD_MUTEX_RECURSIVE ||
133568d75effSDimitry Andric             type == PTHREAD_MUTEX_RECURSIVE_NP)
133668d75effSDimitry Andric           flagz |= MutexFlagWriteReentrant;
133768d75effSDimitry Andric     }
133868d75effSDimitry Andric     MutexCreate(thr, pc, (uptr)m, flagz);
133968d75effSDimitry Andric   }
134068d75effSDimitry Andric   return res;
134168d75effSDimitry Andric }
134268d75effSDimitry Andric 
134368d75effSDimitry Andric TSAN_INTERCEPTOR(int, pthread_mutex_destroy, void *m) {
134468d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(pthread_mutex_destroy, m);
134568d75effSDimitry Andric   int res = REAL(pthread_mutex_destroy)(m);
134668d75effSDimitry Andric   if (res == 0 || res == errno_EBUSY) {
134768d75effSDimitry Andric     MutexDestroy(thr, pc, (uptr)m);
134868d75effSDimitry Andric   }
134968d75effSDimitry Andric   return res;
135068d75effSDimitry Andric }
135168d75effSDimitry Andric 
1352bdd1243dSDimitry Andric TSAN_INTERCEPTOR(int, pthread_mutex_lock, void *m) {
1353bdd1243dSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(pthread_mutex_lock, m);
1354bdd1243dSDimitry Andric   MutexPreLock(thr, pc, (uptr)m);
1355*0fca6ea1SDimitry Andric   int res = BLOCK_REAL(pthread_mutex_lock)(m);
1356bdd1243dSDimitry Andric   if (res == errno_EOWNERDEAD)
1357bdd1243dSDimitry Andric     MutexRepair(thr, pc, (uptr)m);
1358bdd1243dSDimitry Andric   if (res == 0 || res == errno_EOWNERDEAD)
1359bdd1243dSDimitry Andric     MutexPostLock(thr, pc, (uptr)m);
1360bdd1243dSDimitry Andric   if (res == errno_EINVAL)
1361bdd1243dSDimitry Andric     MutexInvalidAccess(thr, pc, (uptr)m);
1362bdd1243dSDimitry Andric   return res;
1363bdd1243dSDimitry Andric }
1364bdd1243dSDimitry Andric 
136568d75effSDimitry Andric TSAN_INTERCEPTOR(int, pthread_mutex_trylock, void *m) {
136668d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(pthread_mutex_trylock, m);
136768d75effSDimitry Andric   int res = REAL(pthread_mutex_trylock)(m);
136868d75effSDimitry Andric   if (res == errno_EOWNERDEAD)
136968d75effSDimitry Andric     MutexRepair(thr, pc, (uptr)m);
137068d75effSDimitry Andric   if (res == 0 || res == errno_EOWNERDEAD)
137168d75effSDimitry Andric     MutexPostLock(thr, pc, (uptr)m, MutexFlagTryLock);
137268d75effSDimitry Andric   return res;
137368d75effSDimitry Andric }
137468d75effSDimitry Andric 
137581ad6265SDimitry Andric #if !SANITIZER_APPLE
137668d75effSDimitry Andric TSAN_INTERCEPTOR(int, pthread_mutex_timedlock, void *m, void *abstime) {
137768d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(pthread_mutex_timedlock, m, abstime);
137868d75effSDimitry Andric   int res = REAL(pthread_mutex_timedlock)(m, abstime);
137968d75effSDimitry Andric   if (res == 0) {
138068d75effSDimitry Andric     MutexPostLock(thr, pc, (uptr)m, MutexFlagTryLock);
138168d75effSDimitry Andric   }
138268d75effSDimitry Andric   return res;
138368d75effSDimitry Andric }
138468d75effSDimitry Andric #endif
138568d75effSDimitry Andric 
1386bdd1243dSDimitry Andric TSAN_INTERCEPTOR(int, pthread_mutex_unlock, void *m) {
1387bdd1243dSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(pthread_mutex_unlock, m);
1388bdd1243dSDimitry Andric   MutexUnlock(thr, pc, (uptr)m);
1389bdd1243dSDimitry Andric   int res = REAL(pthread_mutex_unlock)(m);
1390bdd1243dSDimitry Andric   if (res == errno_EINVAL)
1391bdd1243dSDimitry Andric     MutexInvalidAccess(thr, pc, (uptr)m);
1392bdd1243dSDimitry Andric   return res;
1393bdd1243dSDimitry Andric }
1394bdd1243dSDimitry Andric 
1395cb14a3feSDimitry Andric #if SANITIZER_LINUX
1396cb14a3feSDimitry Andric TSAN_INTERCEPTOR(int, pthread_mutex_clocklock, void *m,
1397cb14a3feSDimitry Andric                  __sanitizer_clockid_t clock, void *abstime) {
1398cb14a3feSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(pthread_mutex_clocklock, m, clock, abstime);
1399cb14a3feSDimitry Andric   MutexPreLock(thr, pc, (uptr)m);
1400*0fca6ea1SDimitry Andric   int res = BLOCK_REAL(pthread_mutex_clocklock)(m, clock, abstime);
1401cb14a3feSDimitry Andric   if (res == errno_EOWNERDEAD)
1402cb14a3feSDimitry Andric     MutexRepair(thr, pc, (uptr)m);
1403cb14a3feSDimitry Andric   if (res == 0 || res == errno_EOWNERDEAD)
1404cb14a3feSDimitry Andric     MutexPostLock(thr, pc, (uptr)m);
1405cb14a3feSDimitry Andric   if (res == errno_EINVAL)
1406cb14a3feSDimitry Andric     MutexInvalidAccess(thr, pc, (uptr)m);
1407cb14a3feSDimitry Andric   return res;
1408cb14a3feSDimitry Andric }
1409cb14a3feSDimitry Andric #endif
1410cb14a3feSDimitry Andric 
1411bdd1243dSDimitry Andric #if SANITIZER_GLIBC
1412bdd1243dSDimitry Andric #  if !__GLIBC_PREREQ(2, 34)
1413bdd1243dSDimitry Andric // glibc 2.34 applies a non-default version for the two functions. They are no
1414bdd1243dSDimitry Andric // longer expected to be intercepted by programs.
1415bdd1243dSDimitry Andric TSAN_INTERCEPTOR(int, __pthread_mutex_lock, void *m) {
1416bdd1243dSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(__pthread_mutex_lock, m);
1417bdd1243dSDimitry Andric   MutexPreLock(thr, pc, (uptr)m);
1418*0fca6ea1SDimitry Andric   int res = BLOCK_REAL(__pthread_mutex_lock)(m);
1419bdd1243dSDimitry Andric   if (res == errno_EOWNERDEAD)
1420bdd1243dSDimitry Andric     MutexRepair(thr, pc, (uptr)m);
1421bdd1243dSDimitry Andric   if (res == 0 || res == errno_EOWNERDEAD)
1422bdd1243dSDimitry Andric     MutexPostLock(thr, pc, (uptr)m);
1423bdd1243dSDimitry Andric   if (res == errno_EINVAL)
1424bdd1243dSDimitry Andric     MutexInvalidAccess(thr, pc, (uptr)m);
1425bdd1243dSDimitry Andric   return res;
1426bdd1243dSDimitry Andric }
1427bdd1243dSDimitry Andric 
1428bdd1243dSDimitry Andric TSAN_INTERCEPTOR(int, __pthread_mutex_unlock, void *m) {
1429bdd1243dSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(__pthread_mutex_unlock, m);
1430bdd1243dSDimitry Andric   MutexUnlock(thr, pc, (uptr)m);
1431bdd1243dSDimitry Andric   int res = REAL(__pthread_mutex_unlock)(m);
1432bdd1243dSDimitry Andric   if (res == errno_EINVAL)
1433bdd1243dSDimitry Andric     MutexInvalidAccess(thr, pc, (uptr)m);
1434bdd1243dSDimitry Andric   return res;
1435bdd1243dSDimitry Andric }
1436bdd1243dSDimitry Andric #  endif
1437bdd1243dSDimitry Andric #endif
1438bdd1243dSDimitry Andric 
143981ad6265SDimitry Andric #if !SANITIZER_APPLE
144068d75effSDimitry Andric TSAN_INTERCEPTOR(int, pthread_spin_init, void *m, int pshared) {
144168d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(pthread_spin_init, m, pshared);
144268d75effSDimitry Andric   int res = REAL(pthread_spin_init)(m, pshared);
144368d75effSDimitry Andric   if (res == 0) {
144468d75effSDimitry Andric     MutexCreate(thr, pc, (uptr)m);
144568d75effSDimitry Andric   }
144668d75effSDimitry Andric   return res;
144768d75effSDimitry Andric }
144868d75effSDimitry Andric 
144968d75effSDimitry Andric TSAN_INTERCEPTOR(int, pthread_spin_destroy, void *m) {
145068d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(pthread_spin_destroy, m);
145168d75effSDimitry Andric   int res = REAL(pthread_spin_destroy)(m);
145268d75effSDimitry Andric   if (res == 0) {
145368d75effSDimitry Andric     MutexDestroy(thr, pc, (uptr)m);
145468d75effSDimitry Andric   }
145568d75effSDimitry Andric   return res;
145668d75effSDimitry Andric }
145768d75effSDimitry Andric 
145868d75effSDimitry Andric TSAN_INTERCEPTOR(int, pthread_spin_lock, void *m) {
145968d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(pthread_spin_lock, m);
146068d75effSDimitry Andric   MutexPreLock(thr, pc, (uptr)m);
1461*0fca6ea1SDimitry Andric   int res = BLOCK_REAL(pthread_spin_lock)(m);
146268d75effSDimitry Andric   if (res == 0) {
146368d75effSDimitry Andric     MutexPostLock(thr, pc, (uptr)m);
146468d75effSDimitry Andric   }
146568d75effSDimitry Andric   return res;
146668d75effSDimitry Andric }
146768d75effSDimitry Andric 
146868d75effSDimitry Andric TSAN_INTERCEPTOR(int, pthread_spin_trylock, void *m) {
146968d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(pthread_spin_trylock, m);
147068d75effSDimitry Andric   int res = REAL(pthread_spin_trylock)(m);
147168d75effSDimitry Andric   if (res == 0) {
147268d75effSDimitry Andric     MutexPostLock(thr, pc, (uptr)m, MutexFlagTryLock);
147368d75effSDimitry Andric   }
147468d75effSDimitry Andric   return res;
147568d75effSDimitry Andric }
147668d75effSDimitry Andric 
147768d75effSDimitry Andric TSAN_INTERCEPTOR(int, pthread_spin_unlock, void *m) {
147868d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(pthread_spin_unlock, m);
147968d75effSDimitry Andric   MutexUnlock(thr, pc, (uptr)m);
148068d75effSDimitry Andric   int res = REAL(pthread_spin_unlock)(m);
148168d75effSDimitry Andric   return res;
148268d75effSDimitry Andric }
148368d75effSDimitry Andric #endif
148468d75effSDimitry Andric 
148568d75effSDimitry Andric TSAN_INTERCEPTOR(int, pthread_rwlock_init, void *m, void *a) {
148668d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_init, m, a);
148768d75effSDimitry Andric   int res = REAL(pthread_rwlock_init)(m, a);
148868d75effSDimitry Andric   if (res == 0) {
148968d75effSDimitry Andric     MutexCreate(thr, pc, (uptr)m);
149068d75effSDimitry Andric   }
149168d75effSDimitry Andric   return res;
149268d75effSDimitry Andric }
149368d75effSDimitry Andric 
149468d75effSDimitry Andric TSAN_INTERCEPTOR(int, pthread_rwlock_destroy, void *m) {
149568d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_destroy, m);
149668d75effSDimitry Andric   int res = REAL(pthread_rwlock_destroy)(m);
149768d75effSDimitry Andric   if (res == 0) {
149868d75effSDimitry Andric     MutexDestroy(thr, pc, (uptr)m);
149968d75effSDimitry Andric   }
150068d75effSDimitry Andric   return res;
150168d75effSDimitry Andric }
150268d75effSDimitry Andric 
150368d75effSDimitry Andric TSAN_INTERCEPTOR(int, pthread_rwlock_rdlock, void *m) {
150468d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_rdlock, m);
150568d75effSDimitry Andric   MutexPreReadLock(thr, pc, (uptr)m);
150668d75effSDimitry Andric   int res = REAL(pthread_rwlock_rdlock)(m);
150768d75effSDimitry Andric   if (res == 0) {
150868d75effSDimitry Andric     MutexPostReadLock(thr, pc, (uptr)m);
150968d75effSDimitry Andric   }
151068d75effSDimitry Andric   return res;
151168d75effSDimitry Andric }
151268d75effSDimitry Andric 
151368d75effSDimitry Andric TSAN_INTERCEPTOR(int, pthread_rwlock_tryrdlock, void *m) {
151468d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_tryrdlock, m);
151568d75effSDimitry Andric   int res = REAL(pthread_rwlock_tryrdlock)(m);
151668d75effSDimitry Andric   if (res == 0) {
151768d75effSDimitry Andric     MutexPostReadLock(thr, pc, (uptr)m, MutexFlagTryLock);
151868d75effSDimitry Andric   }
151968d75effSDimitry Andric   return res;
152068d75effSDimitry Andric }
152168d75effSDimitry Andric 
152281ad6265SDimitry Andric #if !SANITIZER_APPLE
152368d75effSDimitry Andric TSAN_INTERCEPTOR(int, pthread_rwlock_timedrdlock, void *m, void *abstime) {
152468d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_timedrdlock, m, abstime);
152568d75effSDimitry Andric   int res = REAL(pthread_rwlock_timedrdlock)(m, abstime);
152668d75effSDimitry Andric   if (res == 0) {
152768d75effSDimitry Andric     MutexPostReadLock(thr, pc, (uptr)m);
152868d75effSDimitry Andric   }
152968d75effSDimitry Andric   return res;
153068d75effSDimitry Andric }
153168d75effSDimitry Andric #endif
153268d75effSDimitry Andric 
153368d75effSDimitry Andric TSAN_INTERCEPTOR(int, pthread_rwlock_wrlock, void *m) {
153468d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_wrlock, m);
153568d75effSDimitry Andric   MutexPreLock(thr, pc, (uptr)m);
1536*0fca6ea1SDimitry Andric   int res = BLOCK_REAL(pthread_rwlock_wrlock)(m);
153768d75effSDimitry Andric   if (res == 0) {
153868d75effSDimitry Andric     MutexPostLock(thr, pc, (uptr)m);
153968d75effSDimitry Andric   }
154068d75effSDimitry Andric   return res;
154168d75effSDimitry Andric }
154268d75effSDimitry Andric 
154368d75effSDimitry Andric TSAN_INTERCEPTOR(int, pthread_rwlock_trywrlock, void *m) {
154468d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_trywrlock, m);
154568d75effSDimitry Andric   int res = REAL(pthread_rwlock_trywrlock)(m);
154668d75effSDimitry Andric   if (res == 0) {
154768d75effSDimitry Andric     MutexPostLock(thr, pc, (uptr)m, MutexFlagTryLock);
154868d75effSDimitry Andric   }
154968d75effSDimitry Andric   return res;
155068d75effSDimitry Andric }
155168d75effSDimitry Andric 
155281ad6265SDimitry Andric #if !SANITIZER_APPLE
155368d75effSDimitry Andric TSAN_INTERCEPTOR(int, pthread_rwlock_timedwrlock, void *m, void *abstime) {
155468d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_timedwrlock, m, abstime);
155568d75effSDimitry Andric   int res = REAL(pthread_rwlock_timedwrlock)(m, abstime);
155668d75effSDimitry Andric   if (res == 0) {
155768d75effSDimitry Andric     MutexPostLock(thr, pc, (uptr)m, MutexFlagTryLock);
155868d75effSDimitry Andric   }
155968d75effSDimitry Andric   return res;
156068d75effSDimitry Andric }
156168d75effSDimitry Andric #endif
156268d75effSDimitry Andric 
156368d75effSDimitry Andric TSAN_INTERCEPTOR(int, pthread_rwlock_unlock, void *m) {
156468d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_unlock, m);
156568d75effSDimitry Andric   MutexReadOrWriteUnlock(thr, pc, (uptr)m);
156668d75effSDimitry Andric   int res = REAL(pthread_rwlock_unlock)(m);
156768d75effSDimitry Andric   return res;
156868d75effSDimitry Andric }
156968d75effSDimitry Andric 
157081ad6265SDimitry Andric #if !SANITIZER_APPLE
157168d75effSDimitry Andric TSAN_INTERCEPTOR(int, pthread_barrier_init, void *b, void *a, unsigned count) {
157268d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(pthread_barrier_init, b, a, count);
1573349cc55cSDimitry Andric   MemoryAccess(thr, pc, (uptr)b, 1, kAccessWrite);
157468d75effSDimitry Andric   int res = REAL(pthread_barrier_init)(b, a, count);
157568d75effSDimitry Andric   return res;
157668d75effSDimitry Andric }
157768d75effSDimitry Andric 
157868d75effSDimitry Andric TSAN_INTERCEPTOR(int, pthread_barrier_destroy, void *b) {
157968d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(pthread_barrier_destroy, b);
1580349cc55cSDimitry Andric   MemoryAccess(thr, pc, (uptr)b, 1, kAccessWrite);
158168d75effSDimitry Andric   int res = REAL(pthread_barrier_destroy)(b);
158268d75effSDimitry Andric   return res;
158368d75effSDimitry Andric }
158468d75effSDimitry Andric 
158568d75effSDimitry Andric TSAN_INTERCEPTOR(int, pthread_barrier_wait, void *b) {
158668d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(pthread_barrier_wait, b);
158768d75effSDimitry Andric   Release(thr, pc, (uptr)b);
1588349cc55cSDimitry Andric   MemoryAccess(thr, pc, (uptr)b, 1, kAccessRead);
158968d75effSDimitry Andric   int res = REAL(pthread_barrier_wait)(b);
1590349cc55cSDimitry Andric   MemoryAccess(thr, pc, (uptr)b, 1, kAccessRead);
159168d75effSDimitry Andric   if (res == 0 || res == PTHREAD_BARRIER_SERIAL_THREAD) {
159268d75effSDimitry Andric     Acquire(thr, pc, (uptr)b);
159368d75effSDimitry Andric   }
159468d75effSDimitry Andric   return res;
159568d75effSDimitry Andric }
159668d75effSDimitry Andric #endif
159768d75effSDimitry Andric 
159868d75effSDimitry Andric TSAN_INTERCEPTOR(int, pthread_once, void *o, void (*f)()) {
159968d75effSDimitry Andric   SCOPED_INTERCEPTOR_RAW(pthread_once, o, f);
160068d75effSDimitry Andric   if (o == 0 || f == 0)
160168d75effSDimitry Andric     return errno_EINVAL;
160268d75effSDimitry Andric   atomic_uint32_t *a;
160368d75effSDimitry Andric 
160481ad6265SDimitry Andric   if (SANITIZER_APPLE)
160568d75effSDimitry Andric     a = static_cast<atomic_uint32_t*>((void *)((char *)o + sizeof(long_t)));
160668d75effSDimitry Andric   else if (SANITIZER_NETBSD)
160768d75effSDimitry Andric     a = static_cast<atomic_uint32_t*>
160868d75effSDimitry Andric           ((void *)((char *)o + __sanitizer::pthread_mutex_t_sz));
160968d75effSDimitry Andric   else
161068d75effSDimitry Andric     a = static_cast<atomic_uint32_t*>(o);
161168d75effSDimitry Andric 
1612349cc55cSDimitry Andric   // Mac OS X appears to use pthread_once() where calling BlockingRegion hooks
1613349cc55cSDimitry Andric   // result in crashes due to too little stack space.
161481ad6265SDimitry Andric   if (guard_acquire(thr, pc, a, !SANITIZER_APPLE)) {
161568d75effSDimitry Andric     (*f)();
1616349cc55cSDimitry Andric     guard_release(thr, pc, a, kGuardDone);
161768d75effSDimitry Andric   }
161868d75effSDimitry Andric   return 0;
161968d75effSDimitry Andric }
162068d75effSDimitry Andric 
16211fd87a68SDimitry Andric #if SANITIZER_GLIBC
162268d75effSDimitry Andric TSAN_INTERCEPTOR(int, __fxstat, int version, int fd, void *buf) {
162368d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(__fxstat, version, fd, buf);
162468d75effSDimitry Andric   if (fd > 0)
162568d75effSDimitry Andric     FdAccess(thr, pc, fd);
162668d75effSDimitry Andric   return REAL(__fxstat)(version, fd, buf);
162768d75effSDimitry Andric }
162868d75effSDimitry Andric 
162968d75effSDimitry Andric TSAN_INTERCEPTOR(int, __fxstat64, int version, int fd, void *buf) {
163068d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(__fxstat64, version, fd, buf);
163168d75effSDimitry Andric   if (fd > 0)
163268d75effSDimitry Andric     FdAccess(thr, pc, fd);
163368d75effSDimitry Andric   return REAL(__fxstat64)(version, fd, buf);
163468d75effSDimitry Andric }
1635439352acSDimitry Andric #define TSAN_MAYBE_INTERCEPT___FXSTAT TSAN_INTERCEPT(__fxstat); TSAN_INTERCEPT(__fxstat64)
163668d75effSDimitry Andric #else
1637439352acSDimitry Andric #define TSAN_MAYBE_INTERCEPT___FXSTAT
163868d75effSDimitry Andric #endif
163968d75effSDimitry Andric 
1640439352acSDimitry Andric #if !SANITIZER_GLIBC || __GLIBC_PREREQ(2, 33)
1641439352acSDimitry Andric TSAN_INTERCEPTOR(int, fstat, int fd, void *buf) {
1642439352acSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(fstat, fd, buf);
164368d75effSDimitry Andric   if (fd > 0)
164468d75effSDimitry Andric     FdAccess(thr, pc, fd);
1645439352acSDimitry Andric   return REAL(fstat)(fd, buf);
1646439352acSDimitry Andric }
1647439352acSDimitry Andric #  define TSAN_MAYBE_INTERCEPT_FSTAT TSAN_INTERCEPT(fstat)
1648439352acSDimitry Andric #else
1649439352acSDimitry Andric #  define TSAN_MAYBE_INTERCEPT_FSTAT
1650439352acSDimitry Andric #endif
1651439352acSDimitry Andric 
1652439352acSDimitry Andric #if __GLIBC_PREREQ(2, 33)
1653439352acSDimitry Andric TSAN_INTERCEPTOR(int, fstat64, int fd, void *buf) {
1654439352acSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(fstat64, fd, buf);
1655439352acSDimitry Andric   if (fd > 0)
1656439352acSDimitry Andric     FdAccess(thr, pc, fd);
1657439352acSDimitry Andric   return REAL(fstat64)(fd, buf);
165868d75effSDimitry Andric }
165968d75effSDimitry Andric #  define TSAN_MAYBE_INTERCEPT_FSTAT64 TSAN_INTERCEPT(fstat64)
166068d75effSDimitry Andric #else
166168d75effSDimitry Andric #  define TSAN_MAYBE_INTERCEPT_FSTAT64
166268d75effSDimitry Andric #endif
166368d75effSDimitry Andric 
1664e8d8bef9SDimitry Andric TSAN_INTERCEPTOR(int, open, const char *name, int oflag, ...) {
1665e8d8bef9SDimitry Andric   va_list ap;
1666e8d8bef9SDimitry Andric   va_start(ap, oflag);
1667e8d8bef9SDimitry Andric   mode_t mode = va_arg(ap, int);
1668e8d8bef9SDimitry Andric   va_end(ap);
1669e8d8bef9SDimitry Andric   SCOPED_TSAN_INTERCEPTOR(open, name, oflag, mode);
167068d75effSDimitry Andric   READ_STRING(thr, pc, name, 0);
1671e8d8bef9SDimitry Andric   int fd = REAL(open)(name, oflag, mode);
167268d75effSDimitry Andric   if (fd >= 0)
167368d75effSDimitry Andric     FdFileCreate(thr, pc, fd);
167468d75effSDimitry Andric   return fd;
167568d75effSDimitry Andric }
167668d75effSDimitry Andric 
167768d75effSDimitry Andric #if SANITIZER_LINUX
1678e8d8bef9SDimitry Andric TSAN_INTERCEPTOR(int, open64, const char *name, int oflag, ...) {
1679e8d8bef9SDimitry Andric   va_list ap;
1680e8d8bef9SDimitry Andric   va_start(ap, oflag);
1681e8d8bef9SDimitry Andric   mode_t mode = va_arg(ap, int);
1682e8d8bef9SDimitry Andric   va_end(ap);
1683e8d8bef9SDimitry Andric   SCOPED_TSAN_INTERCEPTOR(open64, name, oflag, mode);
168468d75effSDimitry Andric   READ_STRING(thr, pc, name, 0);
1685e8d8bef9SDimitry Andric   int fd = REAL(open64)(name, oflag, mode);
168668d75effSDimitry Andric   if (fd >= 0)
168768d75effSDimitry Andric     FdFileCreate(thr, pc, fd);
168868d75effSDimitry Andric   return fd;
168968d75effSDimitry Andric }
169068d75effSDimitry Andric #define TSAN_MAYBE_INTERCEPT_OPEN64 TSAN_INTERCEPT(open64)
169168d75effSDimitry Andric #else
169268d75effSDimitry Andric #define TSAN_MAYBE_INTERCEPT_OPEN64
169368d75effSDimitry Andric #endif
169468d75effSDimitry Andric 
169568d75effSDimitry Andric TSAN_INTERCEPTOR(int, creat, const char *name, int mode) {
169668d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(creat, name, mode);
169768d75effSDimitry Andric   READ_STRING(thr, pc, name, 0);
169868d75effSDimitry Andric   int fd = REAL(creat)(name, mode);
169968d75effSDimitry Andric   if (fd >= 0)
170068d75effSDimitry Andric     FdFileCreate(thr, pc, fd);
170168d75effSDimitry Andric   return fd;
170268d75effSDimitry Andric }
170368d75effSDimitry Andric 
170468d75effSDimitry Andric #if SANITIZER_LINUX
170568d75effSDimitry Andric TSAN_INTERCEPTOR(int, creat64, const char *name, int mode) {
170668d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(creat64, name, mode);
170768d75effSDimitry Andric   READ_STRING(thr, pc, name, 0);
170868d75effSDimitry Andric   int fd = REAL(creat64)(name, mode);
170968d75effSDimitry Andric   if (fd >= 0)
171068d75effSDimitry Andric     FdFileCreate(thr, pc, fd);
171168d75effSDimitry Andric   return fd;
171268d75effSDimitry Andric }
171368d75effSDimitry Andric #define TSAN_MAYBE_INTERCEPT_CREAT64 TSAN_INTERCEPT(creat64)
171468d75effSDimitry Andric #else
171568d75effSDimitry Andric #define TSAN_MAYBE_INTERCEPT_CREAT64
171668d75effSDimitry Andric #endif
171768d75effSDimitry Andric 
171868d75effSDimitry Andric TSAN_INTERCEPTOR(int, dup, int oldfd) {
171968d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(dup, oldfd);
172068d75effSDimitry Andric   int newfd = REAL(dup)(oldfd);
172168d75effSDimitry Andric   if (oldfd >= 0 && newfd >= 0 && newfd != oldfd)
172268d75effSDimitry Andric     FdDup(thr, pc, oldfd, newfd, true);
172368d75effSDimitry Andric   return newfd;
172468d75effSDimitry Andric }
172568d75effSDimitry Andric 
172668d75effSDimitry Andric TSAN_INTERCEPTOR(int, dup2, int oldfd, int newfd) {
172768d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(dup2, oldfd, newfd);
172868d75effSDimitry Andric   int newfd2 = REAL(dup2)(oldfd, newfd);
172968d75effSDimitry Andric   if (oldfd >= 0 && newfd2 >= 0 && newfd2 != oldfd)
173068d75effSDimitry Andric     FdDup(thr, pc, oldfd, newfd2, false);
173168d75effSDimitry Andric   return newfd2;
173268d75effSDimitry Andric }
173368d75effSDimitry Andric 
173481ad6265SDimitry Andric #if !SANITIZER_APPLE
173568d75effSDimitry Andric TSAN_INTERCEPTOR(int, dup3, int oldfd, int newfd, int flags) {
173668d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(dup3, oldfd, newfd, flags);
173768d75effSDimitry Andric   int newfd2 = REAL(dup3)(oldfd, newfd, flags);
173868d75effSDimitry Andric   if (oldfd >= 0 && newfd2 >= 0 && newfd2 != oldfd)
173968d75effSDimitry Andric     FdDup(thr, pc, oldfd, newfd2, false);
174068d75effSDimitry Andric   return newfd2;
174168d75effSDimitry Andric }
174268d75effSDimitry Andric #endif
174368d75effSDimitry Andric 
174468d75effSDimitry Andric #if SANITIZER_LINUX
174568d75effSDimitry Andric TSAN_INTERCEPTOR(int, eventfd, unsigned initval, int flags) {
174668d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(eventfd, initval, flags);
174768d75effSDimitry Andric   int fd = REAL(eventfd)(initval, flags);
174868d75effSDimitry Andric   if (fd >= 0)
174968d75effSDimitry Andric     FdEventCreate(thr, pc, fd);
175068d75effSDimitry Andric   return fd;
175168d75effSDimitry Andric }
175268d75effSDimitry Andric #define TSAN_MAYBE_INTERCEPT_EVENTFD TSAN_INTERCEPT(eventfd)
175368d75effSDimitry Andric #else
175468d75effSDimitry Andric #define TSAN_MAYBE_INTERCEPT_EVENTFD
175568d75effSDimitry Andric #endif
175668d75effSDimitry Andric 
175768d75effSDimitry Andric #if SANITIZER_LINUX
175868d75effSDimitry Andric TSAN_INTERCEPTOR(int, signalfd, int fd, void *mask, int flags) {
17590eae32dcSDimitry Andric   SCOPED_INTERCEPTOR_RAW(signalfd, fd, mask, flags);
176068d75effSDimitry Andric   FdClose(thr, pc, fd);
176168d75effSDimitry Andric   fd = REAL(signalfd)(fd, mask, flags);
17620eae32dcSDimitry Andric   if (!MustIgnoreInterceptor(thr))
176368d75effSDimitry Andric     FdSignalCreate(thr, pc, fd);
176468d75effSDimitry Andric   return fd;
176568d75effSDimitry Andric }
176668d75effSDimitry Andric #define TSAN_MAYBE_INTERCEPT_SIGNALFD TSAN_INTERCEPT(signalfd)
176768d75effSDimitry Andric #else
176868d75effSDimitry Andric #define TSAN_MAYBE_INTERCEPT_SIGNALFD
176968d75effSDimitry Andric #endif
177068d75effSDimitry Andric 
177168d75effSDimitry Andric #if SANITIZER_LINUX
177268d75effSDimitry Andric TSAN_INTERCEPTOR(int, inotify_init, int fake) {
177368d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(inotify_init, fake);
177468d75effSDimitry Andric   int fd = REAL(inotify_init)(fake);
177568d75effSDimitry Andric   if (fd >= 0)
177668d75effSDimitry Andric     FdInotifyCreate(thr, pc, fd);
177768d75effSDimitry Andric   return fd;
177868d75effSDimitry Andric }
177968d75effSDimitry Andric #define TSAN_MAYBE_INTERCEPT_INOTIFY_INIT TSAN_INTERCEPT(inotify_init)
178068d75effSDimitry Andric #else
178168d75effSDimitry Andric #define TSAN_MAYBE_INTERCEPT_INOTIFY_INIT
178268d75effSDimitry Andric #endif
178368d75effSDimitry Andric 
178468d75effSDimitry Andric #if SANITIZER_LINUX
178568d75effSDimitry Andric TSAN_INTERCEPTOR(int, inotify_init1, int flags) {
178668d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(inotify_init1, flags);
178768d75effSDimitry Andric   int fd = REAL(inotify_init1)(flags);
178868d75effSDimitry Andric   if (fd >= 0)
178968d75effSDimitry Andric     FdInotifyCreate(thr, pc, fd);
179068d75effSDimitry Andric   return fd;
179168d75effSDimitry Andric }
179268d75effSDimitry Andric #define TSAN_MAYBE_INTERCEPT_INOTIFY_INIT1 TSAN_INTERCEPT(inotify_init1)
179368d75effSDimitry Andric #else
179468d75effSDimitry Andric #define TSAN_MAYBE_INTERCEPT_INOTIFY_INIT1
179568d75effSDimitry Andric #endif
179668d75effSDimitry Andric 
179768d75effSDimitry Andric TSAN_INTERCEPTOR(int, socket, int domain, int type, int protocol) {
179868d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(socket, domain, type, protocol);
179968d75effSDimitry Andric   int fd = REAL(socket)(domain, type, protocol);
180068d75effSDimitry Andric   if (fd >= 0)
180168d75effSDimitry Andric     FdSocketCreate(thr, pc, fd);
180268d75effSDimitry Andric   return fd;
180368d75effSDimitry Andric }
180468d75effSDimitry Andric 
180568d75effSDimitry Andric TSAN_INTERCEPTOR(int, socketpair, int domain, int type, int protocol, int *fd) {
180668d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(socketpair, domain, type, protocol, fd);
180768d75effSDimitry Andric   int res = REAL(socketpair)(domain, type, protocol, fd);
180868d75effSDimitry Andric   if (res == 0 && fd[0] >= 0 && fd[1] >= 0)
180968d75effSDimitry Andric     FdPipeCreate(thr, pc, fd[0], fd[1]);
181068d75effSDimitry Andric   return res;
181168d75effSDimitry Andric }
181268d75effSDimitry Andric 
181368d75effSDimitry Andric TSAN_INTERCEPTOR(int, connect, int fd, void *addr, unsigned addrlen) {
181468d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(connect, fd, addr, addrlen);
181568d75effSDimitry Andric   FdSocketConnecting(thr, pc, fd);
181668d75effSDimitry Andric   int res = REAL(connect)(fd, addr, addrlen);
181768d75effSDimitry Andric   if (res == 0 && fd >= 0)
181868d75effSDimitry Andric     FdSocketConnect(thr, pc, fd);
181968d75effSDimitry Andric   return res;
182068d75effSDimitry Andric }
182168d75effSDimitry Andric 
182268d75effSDimitry Andric TSAN_INTERCEPTOR(int, bind, int fd, void *addr, unsigned addrlen) {
182368d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(bind, fd, addr, addrlen);
182468d75effSDimitry Andric   int res = REAL(bind)(fd, addr, addrlen);
182568d75effSDimitry Andric   if (fd > 0 && res == 0)
182668d75effSDimitry Andric     FdAccess(thr, pc, fd);
182768d75effSDimitry Andric   return res;
182868d75effSDimitry Andric }
182968d75effSDimitry Andric 
183068d75effSDimitry Andric TSAN_INTERCEPTOR(int, listen, int fd, int backlog) {
183168d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(listen, fd, backlog);
183268d75effSDimitry Andric   int res = REAL(listen)(fd, backlog);
183368d75effSDimitry Andric   if (fd > 0 && res == 0)
183468d75effSDimitry Andric     FdAccess(thr, pc, fd);
183568d75effSDimitry Andric   return res;
183668d75effSDimitry Andric }
183768d75effSDimitry Andric 
183868d75effSDimitry Andric TSAN_INTERCEPTOR(int, close, int fd) {
18390eae32dcSDimitry Andric   SCOPED_INTERCEPTOR_RAW(close, fd);
184081ad6265SDimitry Andric   if (!in_symbolizer())
184168d75effSDimitry Andric     FdClose(thr, pc, fd);
184268d75effSDimitry Andric   return REAL(close)(fd);
184368d75effSDimitry Andric }
184468d75effSDimitry Andric 
184568d75effSDimitry Andric #if SANITIZER_LINUX
184668d75effSDimitry Andric TSAN_INTERCEPTOR(int, __close, int fd) {
18470eae32dcSDimitry Andric   SCOPED_INTERCEPTOR_RAW(__close, fd);
184868d75effSDimitry Andric   FdClose(thr, pc, fd);
184968d75effSDimitry Andric   return REAL(__close)(fd);
185068d75effSDimitry Andric }
185168d75effSDimitry Andric #define TSAN_MAYBE_INTERCEPT___CLOSE TSAN_INTERCEPT(__close)
185268d75effSDimitry Andric #else
185368d75effSDimitry Andric #define TSAN_MAYBE_INTERCEPT___CLOSE
185468d75effSDimitry Andric #endif
185568d75effSDimitry Andric 
185668d75effSDimitry Andric // glibc guts
185768d75effSDimitry Andric #if SANITIZER_LINUX && !SANITIZER_ANDROID
185868d75effSDimitry Andric TSAN_INTERCEPTOR(void, __res_iclose, void *state, bool free_addr) {
18590eae32dcSDimitry Andric   SCOPED_INTERCEPTOR_RAW(__res_iclose, state, free_addr);
186068d75effSDimitry Andric   int fds[64];
186168d75effSDimitry Andric   int cnt = ExtractResolvFDs(state, fds, ARRAY_SIZE(fds));
18620eae32dcSDimitry Andric   for (int i = 0; i < cnt; i++) FdClose(thr, pc, fds[i]);
186368d75effSDimitry Andric   REAL(__res_iclose)(state, free_addr);
186468d75effSDimitry Andric }
186568d75effSDimitry Andric #define TSAN_MAYBE_INTERCEPT___RES_ICLOSE TSAN_INTERCEPT(__res_iclose)
186668d75effSDimitry Andric #else
186768d75effSDimitry Andric #define TSAN_MAYBE_INTERCEPT___RES_ICLOSE
186868d75effSDimitry Andric #endif
186968d75effSDimitry Andric 
187068d75effSDimitry Andric TSAN_INTERCEPTOR(int, pipe, int *pipefd) {
187168d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(pipe, pipefd);
187268d75effSDimitry Andric   int res = REAL(pipe)(pipefd);
187368d75effSDimitry Andric   if (res == 0 && pipefd[0] >= 0 && pipefd[1] >= 0)
187468d75effSDimitry Andric     FdPipeCreate(thr, pc, pipefd[0], pipefd[1]);
187568d75effSDimitry Andric   return res;
187668d75effSDimitry Andric }
187768d75effSDimitry Andric 
187881ad6265SDimitry Andric #if !SANITIZER_APPLE
187968d75effSDimitry Andric TSAN_INTERCEPTOR(int, pipe2, int *pipefd, int flags) {
188068d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(pipe2, pipefd, flags);
188168d75effSDimitry Andric   int res = REAL(pipe2)(pipefd, flags);
188268d75effSDimitry Andric   if (res == 0 && pipefd[0] >= 0 && pipefd[1] >= 0)
188368d75effSDimitry Andric     FdPipeCreate(thr, pc, pipefd[0], pipefd[1]);
188468d75effSDimitry Andric   return res;
188568d75effSDimitry Andric }
188668d75effSDimitry Andric #endif
188768d75effSDimitry Andric 
188868d75effSDimitry Andric TSAN_INTERCEPTOR(int, unlink, char *path) {
188968d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(unlink, path);
189068d75effSDimitry Andric   Release(thr, pc, File2addr(path));
189168d75effSDimitry Andric   int res = REAL(unlink)(path);
189268d75effSDimitry Andric   return res;
189368d75effSDimitry Andric }
189468d75effSDimitry Andric 
189568d75effSDimitry Andric TSAN_INTERCEPTOR(void*, tmpfile, int fake) {
189668d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(tmpfile, fake);
189768d75effSDimitry Andric   void *res = REAL(tmpfile)(fake);
189868d75effSDimitry Andric   if (res) {
189968d75effSDimitry Andric     int fd = fileno_unlocked(res);
190068d75effSDimitry Andric     if (fd >= 0)
190168d75effSDimitry Andric       FdFileCreate(thr, pc, fd);
190268d75effSDimitry Andric   }
190368d75effSDimitry Andric   return res;
190468d75effSDimitry Andric }
190568d75effSDimitry Andric 
190668d75effSDimitry Andric #if SANITIZER_LINUX
190768d75effSDimitry Andric TSAN_INTERCEPTOR(void*, tmpfile64, int fake) {
190868d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(tmpfile64, fake);
190968d75effSDimitry Andric   void *res = REAL(tmpfile64)(fake);
191068d75effSDimitry Andric   if (res) {
191168d75effSDimitry Andric     int fd = fileno_unlocked(res);
191268d75effSDimitry Andric     if (fd >= 0)
191368d75effSDimitry Andric       FdFileCreate(thr, pc, fd);
191468d75effSDimitry Andric   }
191568d75effSDimitry Andric   return res;
191668d75effSDimitry Andric }
191768d75effSDimitry Andric #define TSAN_MAYBE_INTERCEPT_TMPFILE64 TSAN_INTERCEPT(tmpfile64)
191868d75effSDimitry Andric #else
191968d75effSDimitry Andric #define TSAN_MAYBE_INTERCEPT_TMPFILE64
192068d75effSDimitry Andric #endif
192168d75effSDimitry Andric 
192268d75effSDimitry Andric static void FlushStreams() {
192368d75effSDimitry Andric   // Flushing all the streams here may freeze the process if a child thread is
192468d75effSDimitry Andric   // performing file stream operations at the same time.
192568d75effSDimitry Andric   REAL(fflush)(stdout);
192668d75effSDimitry Andric   REAL(fflush)(stderr);
192768d75effSDimitry Andric }
192868d75effSDimitry Andric 
192968d75effSDimitry Andric TSAN_INTERCEPTOR(void, abort, int fake) {
193068d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(abort, fake);
193168d75effSDimitry Andric   FlushStreams();
193268d75effSDimitry Andric   REAL(abort)(fake);
193368d75effSDimitry Andric }
193468d75effSDimitry Andric 
193568d75effSDimitry Andric TSAN_INTERCEPTOR(int, rmdir, char *path) {
193668d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(rmdir, path);
193768d75effSDimitry Andric   Release(thr, pc, Dir2addr(path));
193868d75effSDimitry Andric   int res = REAL(rmdir)(path);
193968d75effSDimitry Andric   return res;
194068d75effSDimitry Andric }
194168d75effSDimitry Andric 
194268d75effSDimitry Andric TSAN_INTERCEPTOR(int, closedir, void *dirp) {
19430eae32dcSDimitry Andric   SCOPED_INTERCEPTOR_RAW(closedir, dirp);
194468d75effSDimitry Andric   if (dirp) {
194568d75effSDimitry Andric     int fd = dirfd(dirp);
194668d75effSDimitry Andric     FdClose(thr, pc, fd);
194768d75effSDimitry Andric   }
194868d75effSDimitry Andric   return REAL(closedir)(dirp);
194968d75effSDimitry Andric }
195068d75effSDimitry Andric 
195168d75effSDimitry Andric #if SANITIZER_LINUX
195268d75effSDimitry Andric TSAN_INTERCEPTOR(int, epoll_create, int size) {
195368d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(epoll_create, size);
195468d75effSDimitry Andric   int fd = REAL(epoll_create)(size);
195568d75effSDimitry Andric   if (fd >= 0)
195668d75effSDimitry Andric     FdPollCreate(thr, pc, fd);
195768d75effSDimitry Andric   return fd;
195868d75effSDimitry Andric }
195968d75effSDimitry Andric 
196068d75effSDimitry Andric TSAN_INTERCEPTOR(int, epoll_create1, int flags) {
196168d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(epoll_create1, flags);
196268d75effSDimitry Andric   int fd = REAL(epoll_create1)(flags);
196368d75effSDimitry Andric   if (fd >= 0)
196468d75effSDimitry Andric     FdPollCreate(thr, pc, fd);
196568d75effSDimitry Andric   return fd;
196668d75effSDimitry Andric }
196768d75effSDimitry Andric 
196868d75effSDimitry Andric TSAN_INTERCEPTOR(int, epoll_ctl, int epfd, int op, int fd, void *ev) {
196968d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(epoll_ctl, epfd, op, fd, ev);
197068d75effSDimitry Andric   if (epfd >= 0)
197168d75effSDimitry Andric     FdAccess(thr, pc, epfd);
197268d75effSDimitry Andric   if (epfd >= 0 && fd >= 0)
197368d75effSDimitry Andric     FdAccess(thr, pc, fd);
197481ad6265SDimitry Andric   if (op == EPOLL_CTL_ADD && epfd >= 0) {
197581ad6265SDimitry Andric     FdPollAdd(thr, pc, epfd, fd);
197668d75effSDimitry Andric     FdRelease(thr, pc, epfd);
197781ad6265SDimitry Andric   }
197868d75effSDimitry Andric   int res = REAL(epoll_ctl)(epfd, op, fd, ev);
197968d75effSDimitry Andric   return res;
198068d75effSDimitry Andric }
198168d75effSDimitry Andric 
198268d75effSDimitry Andric TSAN_INTERCEPTOR(int, epoll_wait, int epfd, void *ev, int cnt, int timeout) {
198368d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(epoll_wait, epfd, ev, cnt, timeout);
198468d75effSDimitry Andric   if (epfd >= 0)
198568d75effSDimitry Andric     FdAccess(thr, pc, epfd);
198668d75effSDimitry Andric   int res = BLOCK_REAL(epoll_wait)(epfd, ev, cnt, timeout);
198768d75effSDimitry Andric   if (res > 0 && epfd >= 0)
198868d75effSDimitry Andric     FdAcquire(thr, pc, epfd);
198968d75effSDimitry Andric   return res;
199068d75effSDimitry Andric }
199168d75effSDimitry Andric 
199268d75effSDimitry Andric TSAN_INTERCEPTOR(int, epoll_pwait, int epfd, void *ev, int cnt, int timeout,
199368d75effSDimitry Andric                  void *sigmask) {
199468d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(epoll_pwait, epfd, ev, cnt, timeout, sigmask);
199568d75effSDimitry Andric   if (epfd >= 0)
199668d75effSDimitry Andric     FdAccess(thr, pc, epfd);
199768d75effSDimitry Andric   int res = BLOCK_REAL(epoll_pwait)(epfd, ev, cnt, timeout, sigmask);
199868d75effSDimitry Andric   if (res > 0 && epfd >= 0)
199968d75effSDimitry Andric     FdAcquire(thr, pc, epfd);
200068d75effSDimitry Andric   return res;
200168d75effSDimitry Andric }
200268d75effSDimitry Andric 
2003bdd1243dSDimitry Andric TSAN_INTERCEPTOR(int, epoll_pwait2, int epfd, void *ev, int cnt, void *timeout,
2004bdd1243dSDimitry Andric                  void *sigmask) {
2005bdd1243dSDimitry Andric   SCOPED_INTERCEPTOR_RAW(epoll_pwait2, epfd, ev, cnt, timeout, sigmask);
2006bdd1243dSDimitry Andric   // This function is new and may not be present in libc and/or kernel.
2007bdd1243dSDimitry Andric   // Since we effectively add it to libc (as will be probed by the program
2008bdd1243dSDimitry Andric   // using dlsym or a weak function pointer) we need to handle the case
2009bdd1243dSDimitry Andric   // when it's not present in the actual libc.
2010bdd1243dSDimitry Andric   if (!REAL(epoll_pwait2)) {
2011bdd1243dSDimitry Andric     errno = errno_ENOSYS;
2012bdd1243dSDimitry Andric     return -1;
2013bdd1243dSDimitry Andric   }
2014bdd1243dSDimitry Andric   if (MustIgnoreInterceptor(thr))
2015bdd1243dSDimitry Andric     REAL(epoll_pwait2)(epfd, ev, cnt, timeout, sigmask);
2016bdd1243dSDimitry Andric   if (epfd >= 0)
2017bdd1243dSDimitry Andric     FdAccess(thr, pc, epfd);
2018bdd1243dSDimitry Andric   int res = BLOCK_REAL(epoll_pwait2)(epfd, ev, cnt, timeout, sigmask);
2019bdd1243dSDimitry Andric   if (res > 0 && epfd >= 0)
2020bdd1243dSDimitry Andric     FdAcquire(thr, pc, epfd);
2021bdd1243dSDimitry Andric   return res;
2022bdd1243dSDimitry Andric }
2023bdd1243dSDimitry Andric 
202468d75effSDimitry Andric #  define TSAN_MAYBE_INTERCEPT_EPOLL \
202568d75effSDimitry Andric     TSAN_INTERCEPT(epoll_create);    \
202668d75effSDimitry Andric     TSAN_INTERCEPT(epoll_create1);   \
202768d75effSDimitry Andric     TSAN_INTERCEPT(epoll_ctl);       \
202868d75effSDimitry Andric     TSAN_INTERCEPT(epoll_wait);      \
2029bdd1243dSDimitry Andric     TSAN_INTERCEPT(epoll_pwait);     \
2030bdd1243dSDimitry Andric     TSAN_INTERCEPT(epoll_pwait2)
203168d75effSDimitry Andric #else
203268d75effSDimitry Andric #define TSAN_MAYBE_INTERCEPT_EPOLL
203368d75effSDimitry Andric #endif
203468d75effSDimitry Andric 
203568d75effSDimitry Andric // The following functions are intercepted merely to process pending signals.
203668d75effSDimitry Andric // If program blocks signal X, we must deliver the signal before the function
203768d75effSDimitry Andric // returns. Similarly, if program unblocks a signal (or returns from sigsuspend)
203868d75effSDimitry Andric // it's better to deliver the signal straight away.
203968d75effSDimitry Andric TSAN_INTERCEPTOR(int, sigsuspend, const __sanitizer_sigset_t *mask) {
204068d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(sigsuspend, mask);
204168d75effSDimitry Andric   return REAL(sigsuspend)(mask);
204268d75effSDimitry Andric }
204368d75effSDimitry Andric 
204468d75effSDimitry Andric TSAN_INTERCEPTOR(int, sigblock, int mask) {
204568d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(sigblock, mask);
204668d75effSDimitry Andric   return REAL(sigblock)(mask);
204768d75effSDimitry Andric }
204868d75effSDimitry Andric 
204968d75effSDimitry Andric TSAN_INTERCEPTOR(int, sigsetmask, int mask) {
205068d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(sigsetmask, mask);
205168d75effSDimitry Andric   return REAL(sigsetmask)(mask);
205268d75effSDimitry Andric }
205368d75effSDimitry Andric 
205468d75effSDimitry Andric TSAN_INTERCEPTOR(int, pthread_sigmask, int how, const __sanitizer_sigset_t *set,
205568d75effSDimitry Andric     __sanitizer_sigset_t *oldset) {
205668d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(pthread_sigmask, how, set, oldset);
205768d75effSDimitry Andric   return REAL(pthread_sigmask)(how, set, oldset);
205868d75effSDimitry Andric }
205968d75effSDimitry Andric 
206068d75effSDimitry Andric namespace __tsan {
206168d75effSDimitry Andric 
206281ad6265SDimitry Andric static void ReportErrnoSpoiling(ThreadState *thr, uptr pc, int sig) {
2063349cc55cSDimitry Andric   VarSizeStackTrace stack;
2064349cc55cSDimitry Andric   // StackTrace::GetNestInstructionPc(pc) is used because return address is
2065349cc55cSDimitry Andric   // expected, OutputReport() will undo this.
2066349cc55cSDimitry Andric   ObtainCurrentStack(thr, StackTrace::GetNextInstructionPc(pc), &stack);
2067349cc55cSDimitry Andric   ThreadRegistryLock l(&ctx->thread_registry);
2068349cc55cSDimitry Andric   ScopedReport rep(ReportTypeErrnoInSignal);
206981ad6265SDimitry Andric   rep.SetSigNum(sig);
2070349cc55cSDimitry Andric   if (!IsFiredSuppression(ctx, ReportTypeErrnoInSignal, stack)) {
2071349cc55cSDimitry Andric     rep.AddStack(stack, true);
2072349cc55cSDimitry Andric     OutputReport(thr, rep);
2073349cc55cSDimitry Andric   }
2074349cc55cSDimitry Andric }
2075349cc55cSDimitry Andric 
207668d75effSDimitry Andric static void CallUserSignalHandler(ThreadState *thr, bool sync, bool acquire,
2077349cc55cSDimitry Andric                                   int sig, __sanitizer_siginfo *info,
2078349cc55cSDimitry Andric                                   void *uctx) {
20790eae32dcSDimitry Andric   CHECK(thr->slot);
208068d75effSDimitry Andric   __sanitizer_sigaction *sigactions = interceptor_ctx()->sigactions;
208168d75effSDimitry Andric   if (acquire)
208268d75effSDimitry Andric     Acquire(thr, 0, (uptr)&sigactions[sig]);
208368d75effSDimitry Andric   // Signals are generally asynchronous, so if we receive a signals when
208468d75effSDimitry Andric   // ignores are enabled we should disable ignores. This is critical for sync
2085349cc55cSDimitry Andric   // and interceptors, because otherwise we can miss synchronization and report
208668d75effSDimitry Andric   // false races.
208768d75effSDimitry Andric   int ignore_reads_and_writes = thr->ignore_reads_and_writes;
208868d75effSDimitry Andric   int ignore_interceptors = thr->ignore_interceptors;
208968d75effSDimitry Andric   int ignore_sync = thr->ignore_sync;
2090349cc55cSDimitry Andric   // For symbolizer we only process SIGSEGVs synchronously
2091349cc55cSDimitry Andric   // (bug in symbolizer or in tsan). But we want to reset
2092349cc55cSDimitry Andric   // in_symbolizer to fail gracefully. Symbolizer and user code
2093349cc55cSDimitry Andric   // use different memory allocators, so if we don't reset
2094349cc55cSDimitry Andric   // in_symbolizer we can get memory allocated with one being
2095349cc55cSDimitry Andric   // feed with another, which can cause more crashes.
2096349cc55cSDimitry Andric   int in_symbolizer = thr->in_symbolizer;
209768d75effSDimitry Andric   if (!ctx->after_multithreaded_fork) {
209868d75effSDimitry Andric     thr->ignore_reads_and_writes = 0;
209968d75effSDimitry Andric     thr->fast_state.ClearIgnoreBit();
210068d75effSDimitry Andric     thr->ignore_interceptors = 0;
210168d75effSDimitry Andric     thr->ignore_sync = 0;
2102349cc55cSDimitry Andric     thr->in_symbolizer = 0;
210368d75effSDimitry Andric   }
210468d75effSDimitry Andric   // Ensure that the handler does not spoil errno.
210568d75effSDimitry Andric   const int saved_errno = errno;
210668d75effSDimitry Andric   errno = 99;
210768d75effSDimitry Andric   // This code races with sigaction. Be careful to not read sa_sigaction twice.
210868d75effSDimitry Andric   // Also need to remember pc for reporting before the call,
210968d75effSDimitry Andric   // because the handler can reset it.
2110349cc55cSDimitry Andric   volatile uptr pc = (sigactions[sig].sa_flags & SA_SIGINFO)
2111349cc55cSDimitry Andric                          ? (uptr)sigactions[sig].sigaction
2112349cc55cSDimitry Andric                          : (uptr)sigactions[sig].handler;
211368d75effSDimitry Andric   if (pc != sig_dfl && pc != sig_ign) {
2114349cc55cSDimitry Andric     // The callback can be either sa_handler or sa_sigaction.
2115349cc55cSDimitry Andric     // They have different signatures, but we assume that passing
2116349cc55cSDimitry Andric     // additional arguments to sa_handler works and is harmless.
211768d75effSDimitry Andric     ((__sanitizer_sigactionhandler_ptr)pc)(sig, info, uctx);
211868d75effSDimitry Andric   }
211968d75effSDimitry Andric   if (!ctx->after_multithreaded_fork) {
212068d75effSDimitry Andric     thr->ignore_reads_and_writes = ignore_reads_and_writes;
212168d75effSDimitry Andric     if (ignore_reads_and_writes)
212268d75effSDimitry Andric       thr->fast_state.SetIgnoreBit();
212368d75effSDimitry Andric     thr->ignore_interceptors = ignore_interceptors;
212468d75effSDimitry Andric     thr->ignore_sync = ignore_sync;
2125349cc55cSDimitry Andric     thr->in_symbolizer = in_symbolizer;
212668d75effSDimitry Andric   }
212768d75effSDimitry Andric   // We do not detect errno spoiling for SIGTERM,
212868d75effSDimitry Andric   // because some SIGTERM handlers do spoil errno but reraise SIGTERM,
212968d75effSDimitry Andric   // tsan reports false positive in such case.
213068d75effSDimitry Andric   // It's difficult to properly detect this situation (reraise),
213168d75effSDimitry Andric   // because in async signal processing case (when handler is called directly
213268d75effSDimitry Andric   // from rtl_generic_sighandler) we have not yet received the reraised
213368d75effSDimitry Andric   // signal; and it looks too fragile to intercept all ways to reraise a signal.
2134fe6060f1SDimitry Andric   if (ShouldReport(thr, ReportTypeErrnoInSignal) && !sync && sig != SIGTERM &&
2135349cc55cSDimitry Andric       errno != 99)
213681ad6265SDimitry Andric     ReportErrnoSpoiling(thr, pc, sig);
213768d75effSDimitry Andric   errno = saved_errno;
213868d75effSDimitry Andric }
213968d75effSDimitry Andric 
2140349cc55cSDimitry Andric void ProcessPendingSignalsImpl(ThreadState *thr) {
2141349cc55cSDimitry Andric   atomic_store(&thr->pending_signals, 0, memory_order_relaxed);
214268d75effSDimitry Andric   ThreadSignalContext *sctx = SigCtx(thr);
2143349cc55cSDimitry Andric   if (sctx == 0)
214468d75effSDimitry Andric     return;
214568d75effSDimitry Andric   atomic_fetch_add(&thr->in_signal_handler, 1, memory_order_relaxed);
214668d75effSDimitry Andric   internal_sigfillset(&sctx->emptyset);
214768d75effSDimitry Andric   int res = REAL(pthread_sigmask)(SIG_SETMASK, &sctx->emptyset, &sctx->oldset);
214868d75effSDimitry Andric   CHECK_EQ(res, 0);
214968d75effSDimitry Andric   for (int sig = 0; sig < kSigCount; sig++) {
215068d75effSDimitry Andric     SignalDesc *signal = &sctx->pending_signals[sig];
215168d75effSDimitry Andric     if (signal->armed) {
215268d75effSDimitry Andric       signal->armed = false;
2153349cc55cSDimitry Andric       CallUserSignalHandler(thr, false, true, sig, &signal->siginfo,
2154349cc55cSDimitry Andric                             &signal->ctx);
215568d75effSDimitry Andric     }
215668d75effSDimitry Andric   }
215768d75effSDimitry Andric   res = REAL(pthread_sigmask)(SIG_SETMASK, &sctx->oldset, 0);
215868d75effSDimitry Andric   CHECK_EQ(res, 0);
215968d75effSDimitry Andric   atomic_fetch_add(&thr->in_signal_handler, -1, memory_order_relaxed);
216068d75effSDimitry Andric }
216168d75effSDimitry Andric 
216268d75effSDimitry Andric }  // namespace __tsan
216368d75effSDimitry Andric 
2164bdd1243dSDimitry Andric static bool is_sync_signal(ThreadSignalContext *sctx, int sig,
2165bdd1243dSDimitry Andric                            __sanitizer_siginfo *info) {
216668d75effSDimitry Andric   // If we are sending signal to ourselves, we must process it now.
2167bdd1243dSDimitry Andric   if (sctx && sig == sctx->int_signal_send)
2168bdd1243dSDimitry Andric     return true;
2169bdd1243dSDimitry Andric #if SANITIZER_HAS_SIGINFO
2170bdd1243dSDimitry Andric   // POSIX timers can be configured to send any kind of signal; however, it
2171bdd1243dSDimitry Andric   // doesn't make any sense to consider a timer signal as synchronous!
2172bdd1243dSDimitry Andric   if (info->si_code == SI_TIMER)
2173bdd1243dSDimitry Andric     return false;
2174bdd1243dSDimitry Andric #endif
2175bdd1243dSDimitry Andric   return sig == SIGSEGV || sig == SIGBUS || sig == SIGILL || sig == SIGTRAP ||
2176bdd1243dSDimitry Andric          sig == SIGABRT || sig == SIGFPE || sig == SIGPIPE || sig == SIGSYS;
217768d75effSDimitry Andric }
217868d75effSDimitry Andric 
2179349cc55cSDimitry Andric void sighandler(int sig, __sanitizer_siginfo *info, void *ctx) {
2180349cc55cSDimitry Andric   ThreadState *thr = cur_thread_init();
218168d75effSDimitry Andric   ThreadSignalContext *sctx = SigCtx(thr);
218268d75effSDimitry Andric   if (sig < 0 || sig >= kSigCount) {
218368d75effSDimitry Andric     VPrintf(1, "ThreadSanitizer: ignoring signal %d\n", sig);
218468d75effSDimitry Andric     return;
218568d75effSDimitry Andric   }
218668d75effSDimitry Andric   // Don't mess with synchronous signals.
2187bdd1243dSDimitry Andric   const bool sync = is_sync_signal(sctx, sig, info);
218868d75effSDimitry Andric   if (sync ||
218968d75effSDimitry Andric       // If we are in blocking function, we can safely process it now
219068d75effSDimitry Andric       // (but check if we are in a recursive interceptor,
219168d75effSDimitry Andric       // i.e. pthread_join()->munmap()).
2192bdd1243dSDimitry Andric       atomic_load(&thr->in_blocking_func, memory_order_relaxed)) {
219368d75effSDimitry Andric     atomic_fetch_add(&thr->in_signal_handler, 1, memory_order_relaxed);
2194bdd1243dSDimitry Andric     if (atomic_load(&thr->in_blocking_func, memory_order_relaxed)) {
2195bdd1243dSDimitry Andric       atomic_store(&thr->in_blocking_func, 0, memory_order_relaxed);
2196349cc55cSDimitry Andric       CallUserSignalHandler(thr, sync, true, sig, info, ctx);
2197bdd1243dSDimitry Andric       atomic_store(&thr->in_blocking_func, 1, memory_order_relaxed);
219868d75effSDimitry Andric     } else {
219968d75effSDimitry Andric       // Be very conservative with when we do acquire in this case.
220068d75effSDimitry Andric       // It's unsafe to do acquire in async handlers, because ThreadState
220168d75effSDimitry Andric       // can be in inconsistent state.
220268d75effSDimitry Andric       // SIGSYS looks relatively safe -- it's synchronous and can actually
220368d75effSDimitry Andric       // need some global state.
220468d75effSDimitry Andric       bool acq = (sig == SIGSYS);
2205349cc55cSDimitry Andric       CallUserSignalHandler(thr, sync, acq, sig, info, ctx);
220668d75effSDimitry Andric     }
220768d75effSDimitry Andric     atomic_fetch_add(&thr->in_signal_handler, -1, memory_order_relaxed);
220868d75effSDimitry Andric     return;
220968d75effSDimitry Andric   }
221068d75effSDimitry Andric 
221168d75effSDimitry Andric   if (sctx == 0)
221268d75effSDimitry Andric     return;
221368d75effSDimitry Andric   SignalDesc *signal = &sctx->pending_signals[sig];
221468d75effSDimitry Andric   if (signal->armed == false) {
221568d75effSDimitry Andric     signal->armed = true;
221668d75effSDimitry Andric     internal_memcpy(&signal->siginfo, info, sizeof(*info));
221768d75effSDimitry Andric     internal_memcpy(&signal->ctx, ctx, sizeof(signal->ctx));
2218349cc55cSDimitry Andric     atomic_store(&thr->pending_signals, 1, memory_order_relaxed);
221968d75effSDimitry Andric   }
222068d75effSDimitry Andric }
222168d75effSDimitry Andric 
222268d75effSDimitry Andric TSAN_INTERCEPTOR(int, raise, int sig) {
222368d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(raise, sig);
222468d75effSDimitry Andric   ThreadSignalContext *sctx = SigCtx(thr);
222568d75effSDimitry Andric   CHECK_NE(sctx, 0);
222668d75effSDimitry Andric   int prev = sctx->int_signal_send;
222768d75effSDimitry Andric   sctx->int_signal_send = sig;
222868d75effSDimitry Andric   int res = REAL(raise)(sig);
222968d75effSDimitry Andric   CHECK_EQ(sctx->int_signal_send, sig);
223068d75effSDimitry Andric   sctx->int_signal_send = prev;
223168d75effSDimitry Andric   return res;
223268d75effSDimitry Andric }
223368d75effSDimitry Andric 
223468d75effSDimitry Andric TSAN_INTERCEPTOR(int, kill, int pid, int sig) {
223568d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(kill, pid, sig);
223668d75effSDimitry Andric   ThreadSignalContext *sctx = SigCtx(thr);
223768d75effSDimitry Andric   CHECK_NE(sctx, 0);
223868d75effSDimitry Andric   int prev = sctx->int_signal_send;
223968d75effSDimitry Andric   if (pid == (int)internal_getpid()) {
224068d75effSDimitry Andric     sctx->int_signal_send = sig;
224168d75effSDimitry Andric   }
224268d75effSDimitry Andric   int res = REAL(kill)(pid, sig);
224368d75effSDimitry Andric   if (pid == (int)internal_getpid()) {
224468d75effSDimitry Andric     CHECK_EQ(sctx->int_signal_send, sig);
224568d75effSDimitry Andric     sctx->int_signal_send = prev;
224668d75effSDimitry Andric   }
224768d75effSDimitry Andric   return res;
224868d75effSDimitry Andric }
224968d75effSDimitry Andric 
225068d75effSDimitry Andric TSAN_INTERCEPTOR(int, pthread_kill, void *tid, int sig) {
225168d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(pthread_kill, tid, sig);
225268d75effSDimitry Andric   ThreadSignalContext *sctx = SigCtx(thr);
225368d75effSDimitry Andric   CHECK_NE(sctx, 0);
225468d75effSDimitry Andric   int prev = sctx->int_signal_send;
2255349cc55cSDimitry Andric   bool self = pthread_equal(tid, pthread_self());
2256349cc55cSDimitry Andric   if (self)
225768d75effSDimitry Andric     sctx->int_signal_send = sig;
225868d75effSDimitry Andric   int res = REAL(pthread_kill)(tid, sig);
2259349cc55cSDimitry Andric   if (self) {
226068d75effSDimitry Andric     CHECK_EQ(sctx->int_signal_send, sig);
226168d75effSDimitry Andric     sctx->int_signal_send = prev;
226268d75effSDimitry Andric   }
226368d75effSDimitry Andric   return res;
226468d75effSDimitry Andric }
226568d75effSDimitry Andric 
226668d75effSDimitry Andric TSAN_INTERCEPTOR(int, gettimeofday, void *tv, void *tz) {
226768d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(gettimeofday, tv, tz);
226868d75effSDimitry Andric   // It's intercepted merely to process pending signals.
226968d75effSDimitry Andric   return REAL(gettimeofday)(tv, tz);
227068d75effSDimitry Andric }
227168d75effSDimitry Andric 
227268d75effSDimitry Andric TSAN_INTERCEPTOR(int, getaddrinfo, void *node, void *service,
227368d75effSDimitry Andric     void *hints, void *rv) {
227468d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(getaddrinfo, node, service, hints, rv);
227568d75effSDimitry Andric   // We miss atomic synchronization in getaddrinfo,
227668d75effSDimitry Andric   // and can report false race between malloc and free
227768d75effSDimitry Andric   // inside of getaddrinfo. So ignore memory accesses.
227868d75effSDimitry Andric   ThreadIgnoreBegin(thr, pc);
227968d75effSDimitry Andric   int res = REAL(getaddrinfo)(node, service, hints, rv);
2280349cc55cSDimitry Andric   ThreadIgnoreEnd(thr);
228168d75effSDimitry Andric   return res;
228268d75effSDimitry Andric }
228368d75effSDimitry Andric 
228468d75effSDimitry Andric TSAN_INTERCEPTOR(int, fork, int fake) {
228568d75effSDimitry Andric   if (in_symbolizer())
228668d75effSDimitry Andric     return REAL(fork)(fake);
228768d75effSDimitry Andric   SCOPED_INTERCEPTOR_RAW(fork, fake);
2288fe6060f1SDimitry Andric   return REAL(fork)(fake);
228968d75effSDimitry Andric }
2290fe6060f1SDimitry Andric 
2291fe6060f1SDimitry Andric void atfork_prepare() {
2292fe6060f1SDimitry Andric   if (in_symbolizer())
2293fe6060f1SDimitry Andric     return;
2294fe6060f1SDimitry Andric   ThreadState *thr = cur_thread();
2295fe6060f1SDimitry Andric   const uptr pc = StackTrace::GetCurrentPc();
2296fe6060f1SDimitry Andric   ForkBefore(thr, pc);
2297fe6060f1SDimitry Andric }
2298fe6060f1SDimitry Andric 
2299fe6060f1SDimitry Andric void atfork_parent() {
2300fe6060f1SDimitry Andric   if (in_symbolizer())
2301fe6060f1SDimitry Andric     return;
2302fe6060f1SDimitry Andric   ThreadState *thr = cur_thread();
2303fe6060f1SDimitry Andric   const uptr pc = StackTrace::GetCurrentPc();
2304fe6060f1SDimitry Andric   ForkParentAfter(thr, pc);
2305fe6060f1SDimitry Andric }
2306fe6060f1SDimitry Andric 
2307fe6060f1SDimitry Andric void atfork_child() {
2308fe6060f1SDimitry Andric   if (in_symbolizer())
2309fe6060f1SDimitry Andric     return;
2310fe6060f1SDimitry Andric   ThreadState *thr = cur_thread();
2311fe6060f1SDimitry Andric   const uptr pc = StackTrace::GetCurrentPc();
2312349cc55cSDimitry Andric   ForkChildAfter(thr, pc, true);
231368d75effSDimitry Andric   FdOnFork(thr, pc);
231468d75effSDimitry Andric }
231568d75effSDimitry Andric 
231604eeddc0SDimitry Andric #if !SANITIZER_IOS
231768d75effSDimitry Andric TSAN_INTERCEPTOR(int, vfork, int fake) {
231868d75effSDimitry Andric   // Some programs (e.g. openjdk) call close for all file descriptors
231968d75effSDimitry Andric   // in the child process. Under tsan it leads to false positives, because
232068d75effSDimitry Andric   // address space is shared, so the parent process also thinks that
232168d75effSDimitry Andric   // the descriptors are closed (while they are actually not).
232268d75effSDimitry Andric   // This leads to false positives due to missed synchronization.
232368d75effSDimitry Andric   // Strictly saying this is undefined behavior, because vfork child is not
232468d75effSDimitry Andric   // allowed to call any functions other than exec/exit. But this is what
232568d75effSDimitry Andric   // openjdk does, so we want to handle it.
232668d75effSDimitry Andric   // We could disable interceptors in the child process. But it's not possible
232768d75effSDimitry Andric   // to simply intercept and wrap vfork, because vfork child is not allowed
232868d75effSDimitry Andric   // to return from the function that calls vfork, and that's exactly what
232968d75effSDimitry Andric   // we would do. So this would require some assembly trickery as well.
233068d75effSDimitry Andric   // Instead we simply turn vfork into fork.
233168d75effSDimitry Andric   return WRAP(fork)(fake);
233268d75effSDimitry Andric }
233304eeddc0SDimitry Andric #endif
233468d75effSDimitry Andric 
2335349cc55cSDimitry Andric #if SANITIZER_LINUX
2336349cc55cSDimitry Andric TSAN_INTERCEPTOR(int, clone, int (*fn)(void *), void *stack, int flags,
2337349cc55cSDimitry Andric                  void *arg, int *parent_tid, void *tls, pid_t *child_tid) {
2338349cc55cSDimitry Andric   SCOPED_INTERCEPTOR_RAW(clone, fn, stack, flags, arg, parent_tid, tls,
2339349cc55cSDimitry Andric                          child_tid);
2340349cc55cSDimitry Andric   struct Arg {
2341349cc55cSDimitry Andric     int (*fn)(void *);
2342349cc55cSDimitry Andric     void *arg;
2343349cc55cSDimitry Andric   };
2344349cc55cSDimitry Andric   auto wrapper = +[](void *p) -> int {
2345349cc55cSDimitry Andric     auto *thr = cur_thread();
2346349cc55cSDimitry Andric     uptr pc = GET_CURRENT_PC();
2347349cc55cSDimitry Andric     // Start the background thread for fork, but not for clone.
2348349cc55cSDimitry Andric     // For fork we did this always and it's known to work (or user code has
2349349cc55cSDimitry Andric     // adopted). But if we do this for the new clone interceptor some code
2350349cc55cSDimitry Andric     // (sandbox2) fails. So model we used to do for years and don't start the
2351349cc55cSDimitry Andric     // background thread after clone.
2352349cc55cSDimitry Andric     ForkChildAfter(thr, pc, false);
2353349cc55cSDimitry Andric     FdOnFork(thr, pc);
2354349cc55cSDimitry Andric     auto *arg = static_cast<Arg *>(p);
2355349cc55cSDimitry Andric     return arg->fn(arg->arg);
2356349cc55cSDimitry Andric   };
2357349cc55cSDimitry Andric   ForkBefore(thr, pc);
2358349cc55cSDimitry Andric   Arg arg_wrapper = {fn, arg};
2359349cc55cSDimitry Andric   int pid = REAL(clone)(wrapper, stack, flags, &arg_wrapper, parent_tid, tls,
2360349cc55cSDimitry Andric                         child_tid);
2361349cc55cSDimitry Andric   ForkParentAfter(thr, pc);
2362349cc55cSDimitry Andric   return pid;
2363349cc55cSDimitry Andric }
2364349cc55cSDimitry Andric #endif
2365349cc55cSDimitry Andric 
236681ad6265SDimitry Andric #if !SANITIZER_APPLE && !SANITIZER_ANDROID
236768d75effSDimitry Andric typedef int (*dl_iterate_phdr_cb_t)(__sanitizer_dl_phdr_info *info, SIZE_T size,
236868d75effSDimitry Andric                                     void *data);
236968d75effSDimitry Andric struct dl_iterate_phdr_data {
237068d75effSDimitry Andric   ThreadState *thr;
237168d75effSDimitry Andric   uptr pc;
237268d75effSDimitry Andric   dl_iterate_phdr_cb_t cb;
237368d75effSDimitry Andric   void *data;
237468d75effSDimitry Andric };
237568d75effSDimitry Andric 
237668d75effSDimitry Andric static bool IsAppNotRodata(uptr addr) {
23770eae32dcSDimitry Andric   return IsAppMem(addr) && *MemToShadow(addr) != Shadow::kRodata;
237868d75effSDimitry Andric }
237968d75effSDimitry Andric 
238068d75effSDimitry Andric static int dl_iterate_phdr_cb(__sanitizer_dl_phdr_info *info, SIZE_T size,
238168d75effSDimitry Andric                               void *data) {
238268d75effSDimitry Andric   dl_iterate_phdr_data *cbdata = (dl_iterate_phdr_data *)data;
238368d75effSDimitry Andric   // dlopen/dlclose allocate/free dynamic-linker-internal memory, which is later
238468d75effSDimitry Andric   // accessible in dl_iterate_phdr callback. But we don't see synchronization
238568d75effSDimitry Andric   // inside of dynamic linker, so we "unpoison" it here in order to not
238668d75effSDimitry Andric   // produce false reports. Ignoring malloc/free in dlopen/dlclose is not enough
238768d75effSDimitry Andric   // because some libc functions call __libc_dlopen.
238868d75effSDimitry Andric   if (info && IsAppNotRodata((uptr)info->dlpi_name))
238968d75effSDimitry Andric     MemoryResetRange(cbdata->thr, cbdata->pc, (uptr)info->dlpi_name,
239068d75effSDimitry Andric                      internal_strlen(info->dlpi_name));
239168d75effSDimitry Andric   int res = cbdata->cb(info, size, cbdata->data);
239268d75effSDimitry Andric   // Perform the check one more time in case info->dlpi_name was overwritten
239368d75effSDimitry Andric   // by user callback.
239468d75effSDimitry Andric   if (info && IsAppNotRodata((uptr)info->dlpi_name))
239568d75effSDimitry Andric     MemoryResetRange(cbdata->thr, cbdata->pc, (uptr)info->dlpi_name,
239668d75effSDimitry Andric                      internal_strlen(info->dlpi_name));
239768d75effSDimitry Andric   return res;
239868d75effSDimitry Andric }
239968d75effSDimitry Andric 
240068d75effSDimitry Andric TSAN_INTERCEPTOR(int, dl_iterate_phdr, dl_iterate_phdr_cb_t cb, void *data) {
240168d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(dl_iterate_phdr, cb, data);
240268d75effSDimitry Andric   dl_iterate_phdr_data cbdata;
240368d75effSDimitry Andric   cbdata.thr = thr;
240468d75effSDimitry Andric   cbdata.pc = pc;
240568d75effSDimitry Andric   cbdata.cb = cb;
240668d75effSDimitry Andric   cbdata.data = data;
240768d75effSDimitry Andric   int res = REAL(dl_iterate_phdr)(dl_iterate_phdr_cb, &cbdata);
240868d75effSDimitry Andric   return res;
240968d75effSDimitry Andric }
241068d75effSDimitry Andric #endif
241168d75effSDimitry Andric 
241268d75effSDimitry Andric static int OnExit(ThreadState *thr) {
241368d75effSDimitry Andric   int status = Finalize(thr);
241468d75effSDimitry Andric   FlushStreams();
241568d75effSDimitry Andric   return status;
241668d75effSDimitry Andric }
241768d75effSDimitry Andric 
241881ad6265SDimitry Andric #if !SANITIZER_APPLE
241968d75effSDimitry Andric static void HandleRecvmsg(ThreadState *thr, uptr pc,
242068d75effSDimitry Andric     __sanitizer_msghdr *msg) {
242168d75effSDimitry Andric   int fds[64];
242268d75effSDimitry Andric   int cnt = ExtractRecvmsgFDs(msg, fds, ARRAY_SIZE(fds));
242368d75effSDimitry Andric   for (int i = 0; i < cnt; i++)
242468d75effSDimitry Andric     FdEventCreate(thr, pc, fds[i]);
242568d75effSDimitry Andric }
242668d75effSDimitry Andric #endif
242768d75effSDimitry Andric 
242868d75effSDimitry Andric #include "sanitizer_common/sanitizer_platform_interceptors.h"
242968d75effSDimitry Andric // Causes interceptor recursion (getaddrinfo() and fopen())
243068d75effSDimitry Andric #undef SANITIZER_INTERCEPT_GETADDRINFO
243168d75effSDimitry Andric // We define our own.
243268d75effSDimitry Andric #if SANITIZER_INTERCEPT_TLS_GET_ADDR
243368d75effSDimitry Andric #define NEED_TLS_GET_ADDR
243468d75effSDimitry Andric #endif
243568d75effSDimitry Andric #undef SANITIZER_INTERCEPT_TLS_GET_ADDR
2436fe6060f1SDimitry Andric #define SANITIZER_INTERCEPT_TLS_GET_OFFSET 1
243768d75effSDimitry Andric #undef SANITIZER_INTERCEPT_PTHREAD_SIGMASK
243868d75effSDimitry Andric 
243968d75effSDimitry Andric #define COMMON_INTERCEPT_FUNCTION_VER(name, ver)                          \
244068d75effSDimitry Andric   INTERCEPT_FUNCTION_VER(name, ver)
2441fe6060f1SDimitry Andric #define COMMON_INTERCEPT_FUNCTION_VER_UNVERSIONED_FALLBACK(name, ver) \
2442fe6060f1SDimitry Andric   (INTERCEPT_FUNCTION_VER(name, ver) || INTERCEPT_FUNCTION(name))
244368d75effSDimitry Andric 
244468d75effSDimitry Andric #define COMMON_INTERCEPTOR_ENTER_NOIGNORE(ctx, func, ...) \
244568d75effSDimitry Andric   SCOPED_INTERCEPTOR_RAW(func, __VA_ARGS__);              \
2446349cc55cSDimitry Andric   TsanInterceptorContext _ctx = {thr, pc};                \
244768d75effSDimitry Andric   ctx = (void *)&_ctx;                                    \
244868d75effSDimitry Andric   (void)ctx;
244968d75effSDimitry Andric 
245068d75effSDimitry Andric #define COMMON_INTERCEPTOR_FILE_OPEN(ctx, file, path) \
245168d75effSDimitry Andric   if (path)                                           \
245268d75effSDimitry Andric     Acquire(thr, pc, File2addr(path));                \
245368d75effSDimitry Andric   if (file) {                                         \
245468d75effSDimitry Andric     int fd = fileno_unlocked(file);                   \
245568d75effSDimitry Andric     if (fd >= 0) FdFileCreate(thr, pc, fd);           \
245668d75effSDimitry Andric   }
245768d75effSDimitry Andric 
245868d75effSDimitry Andric #define COMMON_INTERCEPTOR_FILE_CLOSE(ctx, file) \
245968d75effSDimitry Andric   if (file) {                                    \
246068d75effSDimitry Andric     int fd = fileno_unlocked(file);              \
24610eae32dcSDimitry Andric     FdClose(thr, pc, fd);                        \
246268d75effSDimitry Andric   }
246368d75effSDimitry Andric 
24644824e7fdSDimitry Andric #define COMMON_INTERCEPTOR_DLOPEN(filename, flag) \
24654824e7fdSDimitry Andric   ({                                              \
24664824e7fdSDimitry Andric     CheckNoDeepBind(filename, flag);              \
24674824e7fdSDimitry Andric     ThreadIgnoreBegin(thr, 0);                    \
24684824e7fdSDimitry Andric     void *res = REAL(dlopen)(filename, flag);     \
24694824e7fdSDimitry Andric     ThreadIgnoreEnd(thr);                         \
24704824e7fdSDimitry Andric     res;                                          \
24714824e7fdSDimitry Andric   })
24724824e7fdSDimitry Andric 
247306c3fb27SDimitry Andric // Ignore interceptors in OnLibraryLoaded()/Unloaded().  These hooks use code
247406c3fb27SDimitry Andric // (ListOfModules::init, MemoryMappingLayout::DumpListOfModules) that make
247506c3fb27SDimitry Andric // intercepted calls, which can cause deadlockes with ReportRace() which also
247606c3fb27SDimitry Andric // uses this code.
247768d75effSDimitry Andric #define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle) \
247806c3fb27SDimitry Andric   ({                                                        \
247906c3fb27SDimitry Andric     ScopedIgnoreInterceptors ignore_interceptors;           \
248006c3fb27SDimitry Andric     libignore()->OnLibraryLoaded(filename);                 \
248106c3fb27SDimitry Andric   })
248268d75effSDimitry Andric 
248368d75effSDimitry Andric #define COMMON_INTERCEPTOR_LIBRARY_UNLOADED()     \
248406c3fb27SDimitry Andric   ({                                              \
248506c3fb27SDimitry Andric     ScopedIgnoreInterceptors ignore_interceptors; \
248606c3fb27SDimitry Andric     libignore()->OnLibraryUnloaded();             \
248706c3fb27SDimitry Andric   })
248868d75effSDimitry Andric 
248968d75effSDimitry Andric #define COMMON_INTERCEPTOR_ACQUIRE(ctx, u) \
249068d75effSDimitry Andric   Acquire(((TsanInterceptorContext *) ctx)->thr, pc, u)
249168d75effSDimitry Andric 
249268d75effSDimitry Andric #define COMMON_INTERCEPTOR_RELEASE(ctx, u) \
249368d75effSDimitry Andric   Release(((TsanInterceptorContext *) ctx)->thr, pc, u)
249468d75effSDimitry Andric 
249568d75effSDimitry Andric #define COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path) \
249668d75effSDimitry Andric   Acquire(((TsanInterceptorContext *) ctx)->thr, pc, Dir2addr(path))
249768d75effSDimitry Andric 
249868d75effSDimitry Andric #define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \
249968d75effSDimitry Andric   FdAcquire(((TsanInterceptorContext *) ctx)->thr, pc, fd)
250068d75effSDimitry Andric 
250168d75effSDimitry Andric #define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \
250268d75effSDimitry Andric   FdRelease(((TsanInterceptorContext *) ctx)->thr, pc, fd)
250368d75effSDimitry Andric 
250468d75effSDimitry Andric #define COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd) \
250568d75effSDimitry Andric   FdAccess(((TsanInterceptorContext *) ctx)->thr, pc, fd)
250668d75effSDimitry Andric 
250768d75effSDimitry Andric #define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \
250868d75effSDimitry Andric   FdSocketAccept(((TsanInterceptorContext *) ctx)->thr, pc, fd, newfd)
250968d75effSDimitry Andric 
251068d75effSDimitry Andric #define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) \
251168d75effSDimitry Andric   ThreadSetName(((TsanInterceptorContext *) ctx)->thr, name)
251268d75effSDimitry Andric 
251368d75effSDimitry Andric #define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name)         \
2514349cc55cSDimitry Andric   if (pthread_equal(pthread_self(), reinterpret_cast<void *>(thread))) \
2515349cc55cSDimitry Andric     COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name);                     \
2516349cc55cSDimitry Andric   else                                                                 \
2517349cc55cSDimitry Andric     __tsan::ctx->thread_registry.SetThreadNameByUserId(thread, name)
251868d75effSDimitry Andric 
251968d75effSDimitry Andric #define COMMON_INTERCEPTOR_BLOCK_REAL(name) BLOCK_REAL(name)
252068d75effSDimitry Andric 
252168d75effSDimitry Andric #define COMMON_INTERCEPTOR_ON_EXIT(ctx) \
252268d75effSDimitry Andric   OnExit(((TsanInterceptorContext *) ctx)->thr)
252368d75effSDimitry Andric 
252468d75effSDimitry Andric #define COMMON_INTERCEPTOR_MMAP_IMPL(ctx, mmap, addr, sz, prot, flags, fd,  \
252568d75effSDimitry Andric                                      off)                                   \
252668d75effSDimitry Andric   do {                                                                      \
252768d75effSDimitry Andric     return mmap_interceptor(thr, pc, REAL(mmap), addr, sz, prot, flags, fd, \
252868d75effSDimitry Andric                             off);                                           \
252968d75effSDimitry Andric   } while (false)
253068d75effSDimitry Andric 
253106c3fb27SDimitry Andric #define COMMON_INTERCEPTOR_MUNMAP_IMPL(ctx, addr, sz)           \
253206c3fb27SDimitry Andric   do {                                                          \
253306c3fb27SDimitry Andric     return munmap_interceptor(thr, pc, REAL(munmap), addr, sz); \
253406c3fb27SDimitry Andric   } while (false)
253506c3fb27SDimitry Andric 
253681ad6265SDimitry Andric #if !SANITIZER_APPLE
253768d75effSDimitry Andric #define COMMON_INTERCEPTOR_HANDLE_RECVMSG(ctx, msg) \
253868d75effSDimitry Andric   HandleRecvmsg(((TsanInterceptorContext *)ctx)->thr, \
253968d75effSDimitry Andric       ((TsanInterceptorContext *)ctx)->pc, msg)
254068d75effSDimitry Andric #endif
254168d75effSDimitry Andric 
254268d75effSDimitry Andric #define COMMON_INTERCEPTOR_GET_TLS_RANGE(begin, end)                           \
254368d75effSDimitry Andric   if (TsanThread *t = GetCurrentThread()) {                                    \
254468d75effSDimitry Andric     *begin = t->tls_begin();                                                   \
254568d75effSDimitry Andric     *end = t->tls_end();                                                       \
254668d75effSDimitry Andric   } else {                                                                     \
254768d75effSDimitry Andric     *begin = *end = 0;                                                         \
254868d75effSDimitry Andric   }
254968d75effSDimitry Andric 
255068d75effSDimitry Andric #define COMMON_INTERCEPTOR_USER_CALLBACK_START() \
255168d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START()
255268d75effSDimitry Andric 
255368d75effSDimitry Andric #define COMMON_INTERCEPTOR_USER_CALLBACK_END() \
255468d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END()
255568d75effSDimitry Andric 
255668d75effSDimitry Andric #include "sanitizer_common/sanitizer_common_interceptors.inc"
255768d75effSDimitry Andric 
255868d75effSDimitry Andric static int sigaction_impl(int sig, const __sanitizer_sigaction *act,
255968d75effSDimitry Andric                           __sanitizer_sigaction *old);
256068d75effSDimitry Andric static __sanitizer_sighandler_ptr signal_impl(int sig,
256168d75effSDimitry Andric                                               __sanitizer_sighandler_ptr h);
256268d75effSDimitry Andric 
256368d75effSDimitry Andric #define SIGNAL_INTERCEPTOR_SIGACTION_IMPL(signo, act, oldact) \
256468d75effSDimitry Andric   { return sigaction_impl(signo, act, oldact); }
256568d75effSDimitry Andric 
256668d75effSDimitry Andric #define SIGNAL_INTERCEPTOR_SIGNAL_IMPL(func, signo, handler) \
256768d75effSDimitry Andric   { return (uptr)signal_impl(signo, (__sanitizer_sighandler_ptr)handler); }
256868d75effSDimitry Andric 
256906c3fb27SDimitry Andric #define SIGNAL_INTERCEPTOR_ENTER() LazyInitialize(cur_thread_init())
257006c3fb27SDimitry Andric 
257168d75effSDimitry Andric #include "sanitizer_common/sanitizer_signal_interceptors.inc"
257268d75effSDimitry Andric 
257368d75effSDimitry Andric int sigaction_impl(int sig, const __sanitizer_sigaction *act,
257468d75effSDimitry Andric                    __sanitizer_sigaction *old) {
257568d75effSDimitry Andric   // Note: if we call REAL(sigaction) directly for any reason without proxying
2576349cc55cSDimitry Andric   // the signal handler through sighandler, very bad things will happen.
257768d75effSDimitry Andric   // The handler will run synchronously and corrupt tsan per-thread state.
257868d75effSDimitry Andric   SCOPED_INTERCEPTOR_RAW(sigaction, sig, act, old);
2579fe6060f1SDimitry Andric   if (sig <= 0 || sig >= kSigCount) {
2580fe6060f1SDimitry Andric     errno = errno_EINVAL;
2581fe6060f1SDimitry Andric     return -1;
2582fe6060f1SDimitry Andric   }
258368d75effSDimitry Andric   __sanitizer_sigaction *sigactions = interceptor_ctx()->sigactions;
258468d75effSDimitry Andric   __sanitizer_sigaction old_stored;
258568d75effSDimitry Andric   if (old) internal_memcpy(&old_stored, &sigactions[sig], sizeof(old_stored));
258668d75effSDimitry Andric   __sanitizer_sigaction newact;
258768d75effSDimitry Andric   if (act) {
258868d75effSDimitry Andric     // Copy act into sigactions[sig].
258968d75effSDimitry Andric     // Can't use struct copy, because compiler can emit call to memcpy.
259068d75effSDimitry Andric     // Can't use internal_memcpy, because it copies byte-by-byte,
25915f757f3fSDimitry Andric     // and signal handler reads the handler concurrently. It can read
259268d75effSDimitry Andric     // some bytes from old value and some bytes from new value.
259368d75effSDimitry Andric     // Use volatile to prevent insertion of memcpy.
259468d75effSDimitry Andric     sigactions[sig].handler =
259568d75effSDimitry Andric         *(volatile __sanitizer_sighandler_ptr const *)&act->handler;
259668d75effSDimitry Andric     sigactions[sig].sa_flags = *(volatile int const *)&act->sa_flags;
259768d75effSDimitry Andric     internal_memcpy(&sigactions[sig].sa_mask, &act->sa_mask,
259868d75effSDimitry Andric                     sizeof(sigactions[sig].sa_mask));
259981ad6265SDimitry Andric #if !SANITIZER_FREEBSD && !SANITIZER_APPLE && !SANITIZER_NETBSD
260068d75effSDimitry Andric     sigactions[sig].sa_restorer = act->sa_restorer;
260168d75effSDimitry Andric #endif
260268d75effSDimitry Andric     internal_memcpy(&newact, act, sizeof(newact));
260368d75effSDimitry Andric     internal_sigfillset(&newact.sa_mask);
2604349cc55cSDimitry Andric     if ((act->sa_flags & SA_SIGINFO) ||
2605349cc55cSDimitry Andric         ((uptr)act->handler != sig_ign && (uptr)act->handler != sig_dfl)) {
2606349cc55cSDimitry Andric       newact.sa_flags |= SA_SIGINFO;
2607349cc55cSDimitry Andric       newact.sigaction = sighandler;
260868d75effSDimitry Andric     }
260968d75effSDimitry Andric     ReleaseStore(thr, pc, (uptr)&sigactions[sig]);
261068d75effSDimitry Andric     act = &newact;
261168d75effSDimitry Andric   }
261268d75effSDimitry Andric   int res = REAL(sigaction)(sig, act, old);
2613349cc55cSDimitry Andric   if (res == 0 && old && old->sigaction == sighandler)
261468d75effSDimitry Andric     internal_memcpy(old, &old_stored, sizeof(*old));
261568d75effSDimitry Andric   return res;
261668d75effSDimitry Andric }
261768d75effSDimitry Andric 
261868d75effSDimitry Andric static __sanitizer_sighandler_ptr signal_impl(int sig,
261968d75effSDimitry Andric                                               __sanitizer_sighandler_ptr h) {
262068d75effSDimitry Andric   __sanitizer_sigaction act;
262168d75effSDimitry Andric   act.handler = h;
262268d75effSDimitry Andric   internal_memset(&act.sa_mask, -1, sizeof(act.sa_mask));
262368d75effSDimitry Andric   act.sa_flags = 0;
262468d75effSDimitry Andric   __sanitizer_sigaction old;
262568d75effSDimitry Andric   int res = sigaction_symname(sig, &act, &old);
262668d75effSDimitry Andric   if (res) return (__sanitizer_sighandler_ptr)sig_err;
262768d75effSDimitry Andric   return old.handler;
262868d75effSDimitry Andric }
262968d75effSDimitry Andric 
263068d75effSDimitry Andric #define TSAN_SYSCALL()             \
263168d75effSDimitry Andric   ThreadState *thr = cur_thread(); \
263268d75effSDimitry Andric   if (thr->ignore_interceptors)    \
263368d75effSDimitry Andric     return;                        \
2634349cc55cSDimitry Andric   ScopedSyscall scoped_syscall(thr)
263568d75effSDimitry Andric 
263668d75effSDimitry Andric struct ScopedSyscall {
263768d75effSDimitry Andric   ThreadState *thr;
263868d75effSDimitry Andric 
2639349cc55cSDimitry Andric   explicit ScopedSyscall(ThreadState *thr) : thr(thr) { LazyInitialize(thr); }
264068d75effSDimitry Andric 
264168d75effSDimitry Andric   ~ScopedSyscall() {
264268d75effSDimitry Andric     ProcessPendingSignals(thr);
264368d75effSDimitry Andric   }
264468d75effSDimitry Andric };
264568d75effSDimitry Andric 
264681ad6265SDimitry Andric #if !SANITIZER_FREEBSD && !SANITIZER_APPLE
264768d75effSDimitry Andric static void syscall_access_range(uptr pc, uptr p, uptr s, bool write) {
264868d75effSDimitry Andric   TSAN_SYSCALL();
264968d75effSDimitry Andric   MemoryAccessRange(thr, pc, p, s, write);
265068d75effSDimitry Andric }
265168d75effSDimitry Andric 
2652e8d8bef9SDimitry Andric static USED void syscall_acquire(uptr pc, uptr addr) {
265368d75effSDimitry Andric   TSAN_SYSCALL();
265468d75effSDimitry Andric   Acquire(thr, pc, addr);
2655349cc55cSDimitry Andric   DPrintf("syscall_acquire(0x%zx))\n", addr);
265668d75effSDimitry Andric }
265768d75effSDimitry Andric 
2658e8d8bef9SDimitry Andric static USED void syscall_release(uptr pc, uptr addr) {
265968d75effSDimitry Andric   TSAN_SYSCALL();
2660349cc55cSDimitry Andric   DPrintf("syscall_release(0x%zx)\n", addr);
266168d75effSDimitry Andric   Release(thr, pc, addr);
266268d75effSDimitry Andric }
266368d75effSDimitry Andric 
266468d75effSDimitry Andric static void syscall_fd_close(uptr pc, int fd) {
26650eae32dcSDimitry Andric   auto *thr = cur_thread();
266668d75effSDimitry Andric   FdClose(thr, pc, fd);
266768d75effSDimitry Andric }
266868d75effSDimitry Andric 
266968d75effSDimitry Andric static USED void syscall_fd_acquire(uptr pc, int fd) {
267068d75effSDimitry Andric   TSAN_SYSCALL();
267168d75effSDimitry Andric   FdAcquire(thr, pc, fd);
2672349cc55cSDimitry Andric   DPrintf("syscall_fd_acquire(%d)\n", fd);
267368d75effSDimitry Andric }
267468d75effSDimitry Andric 
267568d75effSDimitry Andric static USED void syscall_fd_release(uptr pc, int fd) {
267668d75effSDimitry Andric   TSAN_SYSCALL();
2677349cc55cSDimitry Andric   DPrintf("syscall_fd_release(%d)\n", fd);
267868d75effSDimitry Andric   FdRelease(thr, pc, fd);
267968d75effSDimitry Andric }
268068d75effSDimitry Andric 
2681*0fca6ea1SDimitry Andric static USED void sycall_blocking_start() {
2682*0fca6ea1SDimitry Andric   DPrintf("sycall_blocking_start()\n");
2683*0fca6ea1SDimitry Andric   ThreadState *thr = cur_thread();
2684*0fca6ea1SDimitry Andric   EnterBlockingFunc(thr);
2685*0fca6ea1SDimitry Andric   // When we are in a "blocking call", we process signals asynchronously
2686*0fca6ea1SDimitry Andric   // (right when they arrive). In this context we do not expect to be
2687*0fca6ea1SDimitry Andric   // executing any user/runtime code. The known interceptor sequence when
2688*0fca6ea1SDimitry Andric   // this is not true is: pthread_join -> munmap(stack). It's fine
2689*0fca6ea1SDimitry Andric   // to ignore munmap in this case -- we handle stack shadow separately.
2690*0fca6ea1SDimitry Andric   thr->ignore_interceptors++;
2691*0fca6ea1SDimitry Andric }
2692*0fca6ea1SDimitry Andric 
2693*0fca6ea1SDimitry Andric static USED void sycall_blocking_end() {
2694*0fca6ea1SDimitry Andric   DPrintf("sycall_blocking_end()\n");
2695*0fca6ea1SDimitry Andric   ThreadState *thr = cur_thread();
2696*0fca6ea1SDimitry Andric   thr->ignore_interceptors--;
2697*0fca6ea1SDimitry Andric   atomic_store(&thr->in_blocking_func, 0, memory_order_relaxed);
2698*0fca6ea1SDimitry Andric }
2699*0fca6ea1SDimitry Andric 
2700fe6060f1SDimitry Andric static void syscall_pre_fork(uptr pc) { ForkBefore(cur_thread(), pc); }
270168d75effSDimitry Andric 
270268d75effSDimitry Andric static void syscall_post_fork(uptr pc, int pid) {
2703fe6060f1SDimitry Andric   ThreadState *thr = cur_thread();
270468d75effSDimitry Andric   if (pid == 0) {
270568d75effSDimitry Andric     // child
2706349cc55cSDimitry Andric     ForkChildAfter(thr, pc, true);
270768d75effSDimitry Andric     FdOnFork(thr, pc);
270868d75effSDimitry Andric   } else if (pid > 0) {
270968d75effSDimitry Andric     // parent
271068d75effSDimitry Andric     ForkParentAfter(thr, pc);
271168d75effSDimitry Andric   } else {
271268d75effSDimitry Andric     // error
271368d75effSDimitry Andric     ForkParentAfter(thr, pc);
271468d75effSDimitry Andric   }
271568d75effSDimitry Andric }
271668d75effSDimitry Andric #endif
271768d75effSDimitry Andric 
271868d75effSDimitry Andric #define COMMON_SYSCALL_PRE_READ_RANGE(p, s) \
271968d75effSDimitry Andric   syscall_access_range(GET_CALLER_PC(), (uptr)(p), (uptr)(s), false)
272068d75effSDimitry Andric 
272168d75effSDimitry Andric #define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) \
272268d75effSDimitry Andric   syscall_access_range(GET_CALLER_PC(), (uptr)(p), (uptr)(s), true)
272368d75effSDimitry Andric 
272468d75effSDimitry Andric #define COMMON_SYSCALL_POST_READ_RANGE(p, s) \
272568d75effSDimitry Andric   do {                                       \
272668d75effSDimitry Andric     (void)(p);                               \
272768d75effSDimitry Andric     (void)(s);                               \
272868d75effSDimitry Andric   } while (false)
272968d75effSDimitry Andric 
273068d75effSDimitry Andric #define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) \
273168d75effSDimitry Andric   do {                                        \
273268d75effSDimitry Andric     (void)(p);                                \
273368d75effSDimitry Andric     (void)(s);                                \
273468d75effSDimitry Andric   } while (false)
273568d75effSDimitry Andric 
273668d75effSDimitry Andric #define COMMON_SYSCALL_ACQUIRE(addr) \
273768d75effSDimitry Andric     syscall_acquire(GET_CALLER_PC(), (uptr)(addr))
273868d75effSDimitry Andric 
273968d75effSDimitry Andric #define COMMON_SYSCALL_RELEASE(addr) \
274068d75effSDimitry Andric     syscall_release(GET_CALLER_PC(), (uptr)(addr))
274168d75effSDimitry Andric 
274268d75effSDimitry Andric #define COMMON_SYSCALL_FD_CLOSE(fd) syscall_fd_close(GET_CALLER_PC(), fd)
274368d75effSDimitry Andric 
274468d75effSDimitry Andric #define COMMON_SYSCALL_FD_ACQUIRE(fd) syscall_fd_acquire(GET_CALLER_PC(), fd)
274568d75effSDimitry Andric 
274668d75effSDimitry Andric #define COMMON_SYSCALL_FD_RELEASE(fd) syscall_fd_release(GET_CALLER_PC(), fd)
274768d75effSDimitry Andric 
274868d75effSDimitry Andric #define COMMON_SYSCALL_PRE_FORK() \
274968d75effSDimitry Andric   syscall_pre_fork(GET_CALLER_PC())
275068d75effSDimitry Andric 
275168d75effSDimitry Andric #define COMMON_SYSCALL_POST_FORK(res) \
275268d75effSDimitry Andric   syscall_post_fork(GET_CALLER_PC(), res)
275368d75effSDimitry Andric 
2754*0fca6ea1SDimitry Andric #define COMMON_SYSCALL_BLOCKING_START() sycall_blocking_start()
2755*0fca6ea1SDimitry Andric #define COMMON_SYSCALL_BLOCKING_END() sycall_blocking_end()
2756*0fca6ea1SDimitry Andric 
275768d75effSDimitry Andric #include "sanitizer_common/sanitizer_common_syscalls.inc"
275868d75effSDimitry Andric #include "sanitizer_common/sanitizer_syscalls_netbsd.inc"
275968d75effSDimitry Andric 
276068d75effSDimitry Andric #ifdef NEED_TLS_GET_ADDR
2761fe6060f1SDimitry Andric 
2762fe6060f1SDimitry Andric static void handle_tls_addr(void *arg, void *res) {
2763fe6060f1SDimitry Andric   ThreadState *thr = cur_thread();
2764fe6060f1SDimitry Andric   if (!thr)
2765fe6060f1SDimitry Andric     return;
2766fe6060f1SDimitry Andric   DTLS::DTV *dtv = DTLS_on_tls_get_addr(arg, res, thr->tls_addr,
2767fe6060f1SDimitry Andric                                         thr->tls_addr + thr->tls_size);
2768fe6060f1SDimitry Andric   if (!dtv)
2769fe6060f1SDimitry Andric     return;
2770fe6060f1SDimitry Andric   // New DTLS block has been allocated.
2771fe6060f1SDimitry Andric   MemoryResetRange(thr, 0, dtv->beg, dtv->size);
2772fe6060f1SDimitry Andric }
2773fe6060f1SDimitry Andric 
2774fe6060f1SDimitry Andric #if !SANITIZER_S390
277568d75effSDimitry Andric // Define own interceptor instead of sanitizer_common's for three reasons:
277668d75effSDimitry Andric // 1. It must not process pending signals.
277768d75effSDimitry Andric //    Signal handlers may contain MOVDQA instruction (see below).
277868d75effSDimitry Andric // 2. It must be as simple as possible to not contain MOVDQA.
277968d75effSDimitry Andric // 3. Sanitizer_common version uses COMMON_INTERCEPTOR_INITIALIZE_RANGE which
278068d75effSDimitry Andric //    is empty for tsan (meant only for msan).
278168d75effSDimitry Andric // Note: __tls_get_addr can be called with mis-aligned stack due to:
278268d75effSDimitry Andric // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58066
278368d75effSDimitry Andric // So the interceptor must work with mis-aligned stack, in particular, does not
278468d75effSDimitry Andric // execute MOVDQA with stack addresses.
278568d75effSDimitry Andric TSAN_INTERCEPTOR(void *, __tls_get_addr, void *arg) {
278668d75effSDimitry Andric   void *res = REAL(__tls_get_addr)(arg);
2787fe6060f1SDimitry Andric   handle_tls_addr(arg, res);
278868d75effSDimitry Andric   return res;
278968d75effSDimitry Andric }
2790fe6060f1SDimitry Andric #else // SANITIZER_S390
2791fe6060f1SDimitry Andric TSAN_INTERCEPTOR(uptr, __tls_get_addr_internal, void *arg) {
2792fe6060f1SDimitry Andric   uptr res = __tls_get_offset_wrapper(arg, REAL(__tls_get_offset));
2793fe6060f1SDimitry Andric   char *tp = static_cast<char *>(__builtin_thread_pointer());
2794fe6060f1SDimitry Andric   handle_tls_addr(arg, res + tp);
2795fe6060f1SDimitry Andric   return res;
2796fe6060f1SDimitry Andric }
2797fe6060f1SDimitry Andric #endif
279868d75effSDimitry Andric #endif
279968d75effSDimitry Andric 
280068d75effSDimitry Andric #if SANITIZER_NETBSD
280168d75effSDimitry Andric TSAN_INTERCEPTOR(void, _lwp_exit) {
280268d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(_lwp_exit);
280368d75effSDimitry Andric   DestroyThreadState();
280468d75effSDimitry Andric   REAL(_lwp_exit)();
280568d75effSDimitry Andric }
280668d75effSDimitry Andric #define TSAN_MAYBE_INTERCEPT__LWP_EXIT TSAN_INTERCEPT(_lwp_exit)
280768d75effSDimitry Andric #else
280868d75effSDimitry Andric #define TSAN_MAYBE_INTERCEPT__LWP_EXIT
280968d75effSDimitry Andric #endif
281068d75effSDimitry Andric 
281168d75effSDimitry Andric #if SANITIZER_FREEBSD
281268d75effSDimitry Andric TSAN_INTERCEPTOR(void, thr_exit, tid_t *state) {
281368d75effSDimitry Andric   SCOPED_TSAN_INTERCEPTOR(thr_exit, state);
281468d75effSDimitry Andric   DestroyThreadState();
281568d75effSDimitry Andric   REAL(thr_exit(state));
281668d75effSDimitry Andric }
281768d75effSDimitry Andric #define TSAN_MAYBE_INTERCEPT_THR_EXIT TSAN_INTERCEPT(thr_exit)
281868d75effSDimitry Andric #else
281968d75effSDimitry Andric #define TSAN_MAYBE_INTERCEPT_THR_EXIT
282068d75effSDimitry Andric #endif
282168d75effSDimitry Andric 
28221c21bfb1SDimitry Andric TSAN_INTERCEPTOR_FREEBSD_ALIAS(int, cond_init, void *c, void *a)
28231c21bfb1SDimitry Andric TSAN_INTERCEPTOR_FREEBSD_ALIAS(int, cond_destroy, void *c)
28241c21bfb1SDimitry Andric TSAN_INTERCEPTOR_FREEBSD_ALIAS(int, cond_signal, void *c)
28251c21bfb1SDimitry Andric TSAN_INTERCEPTOR_FREEBSD_ALIAS(int, cond_broadcast, void *c)
28261c21bfb1SDimitry Andric TSAN_INTERCEPTOR_FREEBSD_ALIAS(int, cond_wait, void *c, void *m)
28271c21bfb1SDimitry Andric TSAN_INTERCEPTOR_FREEBSD_ALIAS(int, mutex_init, void *m, void *a)
28281c21bfb1SDimitry Andric TSAN_INTERCEPTOR_FREEBSD_ALIAS(int, mutex_destroy, void *m)
28291c21bfb1SDimitry Andric TSAN_INTERCEPTOR_FREEBSD_ALIAS(int, mutex_lock, void *m)
28301c21bfb1SDimitry Andric TSAN_INTERCEPTOR_FREEBSD_ALIAS(int, mutex_trylock, void *m)
28311c21bfb1SDimitry Andric TSAN_INTERCEPTOR_FREEBSD_ALIAS(int, mutex_unlock, void *m)
28321c21bfb1SDimitry Andric TSAN_INTERCEPTOR_FREEBSD_ALIAS(int, rwlock_init, void *l, void *a)
28331c21bfb1SDimitry Andric TSAN_INTERCEPTOR_FREEBSD_ALIAS(int, rwlock_destroy, void *l)
28341c21bfb1SDimitry Andric TSAN_INTERCEPTOR_FREEBSD_ALIAS(int, rwlock_rdlock, void *l)
28351c21bfb1SDimitry Andric TSAN_INTERCEPTOR_FREEBSD_ALIAS(int, rwlock_tryrdlock, void *l)
28361c21bfb1SDimitry Andric TSAN_INTERCEPTOR_FREEBSD_ALIAS(int, rwlock_wrlock, void *l)
28371c21bfb1SDimitry Andric TSAN_INTERCEPTOR_FREEBSD_ALIAS(int, rwlock_trywrlock, void *l)
28381c21bfb1SDimitry Andric TSAN_INTERCEPTOR_FREEBSD_ALIAS(int, rwlock_unlock, void *l)
28391c21bfb1SDimitry Andric TSAN_INTERCEPTOR_FREEBSD_ALIAS(int, once, void *o, void (*i)())
28401c21bfb1SDimitry Andric TSAN_INTERCEPTOR_FREEBSD_ALIAS(int, sigmask, int f, void *n, void *o)
28411c21bfb1SDimitry Andric 
284268d75effSDimitry Andric TSAN_INTERCEPTOR_NETBSD_ALIAS(int, cond_init, void *c, void *a)
284368d75effSDimitry Andric TSAN_INTERCEPTOR_NETBSD_ALIAS(int, cond_signal, void *c)
284468d75effSDimitry Andric TSAN_INTERCEPTOR_NETBSD_ALIAS(int, cond_broadcast, void *c)
284568d75effSDimitry Andric TSAN_INTERCEPTOR_NETBSD_ALIAS(int, cond_wait, void *c, void *m)
284668d75effSDimitry Andric TSAN_INTERCEPTOR_NETBSD_ALIAS(int, cond_destroy, void *c)
284768d75effSDimitry Andric TSAN_INTERCEPTOR_NETBSD_ALIAS(int, mutex_init, void *m, void *a)
284868d75effSDimitry Andric TSAN_INTERCEPTOR_NETBSD_ALIAS(int, mutex_destroy, void *m)
2849bdd1243dSDimitry Andric TSAN_INTERCEPTOR_NETBSD_ALIAS(int, mutex_lock, void *m)
285068d75effSDimitry Andric TSAN_INTERCEPTOR_NETBSD_ALIAS(int, mutex_trylock, void *m)
2851bdd1243dSDimitry Andric TSAN_INTERCEPTOR_NETBSD_ALIAS(int, mutex_unlock, void *m)
285268d75effSDimitry Andric TSAN_INTERCEPTOR_NETBSD_ALIAS(int, rwlock_init, void *m, void *a)
285368d75effSDimitry Andric TSAN_INTERCEPTOR_NETBSD_ALIAS(int, rwlock_destroy, void *m)
285468d75effSDimitry Andric TSAN_INTERCEPTOR_NETBSD_ALIAS(int, rwlock_rdlock, void *m)
285568d75effSDimitry Andric TSAN_INTERCEPTOR_NETBSD_ALIAS(int, rwlock_tryrdlock, void *m)
285668d75effSDimitry Andric TSAN_INTERCEPTOR_NETBSD_ALIAS(int, rwlock_wrlock, void *m)
285768d75effSDimitry Andric TSAN_INTERCEPTOR_NETBSD_ALIAS(int, rwlock_trywrlock, void *m)
285868d75effSDimitry Andric TSAN_INTERCEPTOR_NETBSD_ALIAS(int, rwlock_unlock, void *m)
285968d75effSDimitry Andric TSAN_INTERCEPTOR_NETBSD_ALIAS_THR(int, once, void *o, void (*f)())
286068d75effSDimitry Andric TSAN_INTERCEPTOR_NETBSD_ALIAS_THR2(int, sigsetmask, sigmask, int a, void *b,
286168d75effSDimitry Andric   void *c)
286268d75effSDimitry Andric 
286368d75effSDimitry Andric namespace __tsan {
286468d75effSDimitry Andric 
286568d75effSDimitry Andric static void finalize(void *arg) {
286668d75effSDimitry Andric   ThreadState *thr = cur_thread();
286768d75effSDimitry Andric   int status = Finalize(thr);
286868d75effSDimitry Andric   // Make sure the output is not lost.
286968d75effSDimitry Andric   FlushStreams();
287068d75effSDimitry Andric   if (status)
287168d75effSDimitry Andric     Die();
287268d75effSDimitry Andric }
287368d75effSDimitry Andric 
287481ad6265SDimitry Andric #if !SANITIZER_APPLE && !SANITIZER_ANDROID
287568d75effSDimitry Andric static void unreachable() {
287668d75effSDimitry Andric   Report("FATAL: ThreadSanitizer: unreachable called\n");
287768d75effSDimitry Andric   Die();
287868d75effSDimitry Andric }
287968d75effSDimitry Andric #endif
288068d75effSDimitry Andric 
288168d75effSDimitry Andric // Define default implementation since interception of libdispatch  is optional.
288268d75effSDimitry Andric SANITIZER_WEAK_ATTRIBUTE void InitializeLibdispatchInterceptors() {}
288368d75effSDimitry Andric 
288468d75effSDimitry Andric void InitializeInterceptors() {
288581ad6265SDimitry Andric #if !SANITIZER_APPLE
288668d75effSDimitry Andric   // We need to setup it early, because functions like dlsym() can call it.
288768d75effSDimitry Andric   REAL(memset) = internal_memset;
288868d75effSDimitry Andric   REAL(memcpy) = internal_memcpy;
288968d75effSDimitry Andric #endif
289068d75effSDimitry Andric 
2891*0fca6ea1SDimitry Andric   __interception::DoesNotSupportStaticLinking();
2892*0fca6ea1SDimitry Andric 
289368d75effSDimitry Andric   new(interceptor_ctx()) InterceptorContext();
289468d75effSDimitry Andric 
2895*0fca6ea1SDimitry Andric   // Interpose __tls_get_addr before the common interposers. This is needed
2896*0fca6ea1SDimitry Andric   // because dlsym() may call malloc on failure which could result in other
2897*0fca6ea1SDimitry Andric   // interposed functions being called that could eventually make use of TLS.
2898*0fca6ea1SDimitry Andric #ifdef NEED_TLS_GET_ADDR
2899*0fca6ea1SDimitry Andric #  if !SANITIZER_S390
2900*0fca6ea1SDimitry Andric   TSAN_INTERCEPT(__tls_get_addr);
2901*0fca6ea1SDimitry Andric #  else
2902*0fca6ea1SDimitry Andric   TSAN_INTERCEPT(__tls_get_addr_internal);
2903*0fca6ea1SDimitry Andric   TSAN_INTERCEPT(__tls_get_offset);
2904*0fca6ea1SDimitry Andric #  endif
2905*0fca6ea1SDimitry Andric #endif
290668d75effSDimitry Andric   InitializeCommonInterceptors();
290768d75effSDimitry Andric   InitializeSignalInterceptors();
290868d75effSDimitry Andric   InitializeLibdispatchInterceptors();
290968d75effSDimitry Andric 
291081ad6265SDimitry Andric #if !SANITIZER_APPLE
291106c3fb27SDimitry Andric   InitializeSetjmpInterceptors();
291268d75effSDimitry Andric #endif
291368d75effSDimitry Andric 
291468d75effSDimitry Andric   TSAN_INTERCEPT(longjmp_symname);
291568d75effSDimitry Andric   TSAN_INTERCEPT(siglongjmp_symname);
291668d75effSDimitry Andric #if SANITIZER_NETBSD
291768d75effSDimitry Andric   TSAN_INTERCEPT(_longjmp);
291868d75effSDimitry Andric #endif
291968d75effSDimitry Andric 
292068d75effSDimitry Andric   TSAN_INTERCEPT(malloc);
292168d75effSDimitry Andric   TSAN_INTERCEPT(__libc_memalign);
292268d75effSDimitry Andric   TSAN_INTERCEPT(calloc);
292368d75effSDimitry Andric   TSAN_INTERCEPT(realloc);
292468d75effSDimitry Andric   TSAN_INTERCEPT(reallocarray);
292568d75effSDimitry Andric   TSAN_INTERCEPT(free);
292668d75effSDimitry Andric   TSAN_INTERCEPT(cfree);
292768d75effSDimitry Andric   TSAN_INTERCEPT(munmap);
292868d75effSDimitry Andric   TSAN_MAYBE_INTERCEPT_MEMALIGN;
292968d75effSDimitry Andric   TSAN_INTERCEPT(valloc);
293068d75effSDimitry Andric   TSAN_MAYBE_INTERCEPT_PVALLOC;
293168d75effSDimitry Andric   TSAN_INTERCEPT(posix_memalign);
293268d75effSDimitry Andric 
293368d75effSDimitry Andric   TSAN_INTERCEPT(strcpy);
293468d75effSDimitry Andric   TSAN_INTERCEPT(strncpy);
293568d75effSDimitry Andric   TSAN_INTERCEPT(strdup);
293668d75effSDimitry Andric 
293768d75effSDimitry Andric   TSAN_INTERCEPT(pthread_create);
293868d75effSDimitry Andric   TSAN_INTERCEPT(pthread_join);
293968d75effSDimitry Andric   TSAN_INTERCEPT(pthread_detach);
294068d75effSDimitry Andric   TSAN_INTERCEPT(pthread_exit);
294168d75effSDimitry Andric   #if SANITIZER_LINUX
294268d75effSDimitry Andric   TSAN_INTERCEPT(pthread_tryjoin_np);
294368d75effSDimitry Andric   TSAN_INTERCEPT(pthread_timedjoin_np);
294468d75effSDimitry Andric   #endif
294568d75effSDimitry Andric 
294668d75effSDimitry Andric   TSAN_INTERCEPT_VER(pthread_cond_init, PTHREAD_ABI_BASE);
294768d75effSDimitry Andric   TSAN_INTERCEPT_VER(pthread_cond_signal, PTHREAD_ABI_BASE);
294868d75effSDimitry Andric   TSAN_INTERCEPT_VER(pthread_cond_broadcast, PTHREAD_ABI_BASE);
294968d75effSDimitry Andric   TSAN_INTERCEPT_VER(pthread_cond_wait, PTHREAD_ABI_BASE);
295068d75effSDimitry Andric   TSAN_INTERCEPT_VER(pthread_cond_timedwait, PTHREAD_ABI_BASE);
295168d75effSDimitry Andric   TSAN_INTERCEPT_VER(pthread_cond_destroy, PTHREAD_ABI_BASE);
295268d75effSDimitry Andric 
2953e8d8bef9SDimitry Andric   TSAN_MAYBE_PTHREAD_COND_CLOCKWAIT;
2954e8d8bef9SDimitry Andric 
295568d75effSDimitry Andric   TSAN_INTERCEPT(pthread_mutex_init);
295668d75effSDimitry Andric   TSAN_INTERCEPT(pthread_mutex_destroy);
2957bdd1243dSDimitry Andric   TSAN_INTERCEPT(pthread_mutex_lock);
295868d75effSDimitry Andric   TSAN_INTERCEPT(pthread_mutex_trylock);
295968d75effSDimitry Andric   TSAN_INTERCEPT(pthread_mutex_timedlock);
2960bdd1243dSDimitry Andric   TSAN_INTERCEPT(pthread_mutex_unlock);
2961cb14a3feSDimitry Andric #if SANITIZER_LINUX
2962cb14a3feSDimitry Andric   TSAN_INTERCEPT(pthread_mutex_clocklock);
2963cb14a3feSDimitry Andric #endif
2964bdd1243dSDimitry Andric #if SANITIZER_GLIBC
2965bdd1243dSDimitry Andric #  if !__GLIBC_PREREQ(2, 34)
2966bdd1243dSDimitry Andric   TSAN_INTERCEPT(__pthread_mutex_lock);
2967bdd1243dSDimitry Andric   TSAN_INTERCEPT(__pthread_mutex_unlock);
2968bdd1243dSDimitry Andric #  endif
2969bdd1243dSDimitry Andric #endif
297068d75effSDimitry Andric 
297168d75effSDimitry Andric   TSAN_INTERCEPT(pthread_spin_init);
297268d75effSDimitry Andric   TSAN_INTERCEPT(pthread_spin_destroy);
297368d75effSDimitry Andric   TSAN_INTERCEPT(pthread_spin_lock);
297468d75effSDimitry Andric   TSAN_INTERCEPT(pthread_spin_trylock);
297568d75effSDimitry Andric   TSAN_INTERCEPT(pthread_spin_unlock);
297668d75effSDimitry Andric 
297768d75effSDimitry Andric   TSAN_INTERCEPT(pthread_rwlock_init);
297868d75effSDimitry Andric   TSAN_INTERCEPT(pthread_rwlock_destroy);
297968d75effSDimitry Andric   TSAN_INTERCEPT(pthread_rwlock_rdlock);
298068d75effSDimitry Andric   TSAN_INTERCEPT(pthread_rwlock_tryrdlock);
298168d75effSDimitry Andric   TSAN_INTERCEPT(pthread_rwlock_timedrdlock);
298268d75effSDimitry Andric   TSAN_INTERCEPT(pthread_rwlock_wrlock);
298368d75effSDimitry Andric   TSAN_INTERCEPT(pthread_rwlock_trywrlock);
298468d75effSDimitry Andric   TSAN_INTERCEPT(pthread_rwlock_timedwrlock);
298568d75effSDimitry Andric   TSAN_INTERCEPT(pthread_rwlock_unlock);
298668d75effSDimitry Andric 
298768d75effSDimitry Andric   TSAN_INTERCEPT(pthread_barrier_init);
298868d75effSDimitry Andric   TSAN_INTERCEPT(pthread_barrier_destroy);
298968d75effSDimitry Andric   TSAN_INTERCEPT(pthread_barrier_wait);
299068d75effSDimitry Andric 
299168d75effSDimitry Andric   TSAN_INTERCEPT(pthread_once);
299268d75effSDimitry Andric 
299368d75effSDimitry Andric   TSAN_MAYBE_INTERCEPT___FXSTAT;
2994439352acSDimitry Andric   TSAN_MAYBE_INTERCEPT_FSTAT;
299568d75effSDimitry Andric   TSAN_MAYBE_INTERCEPT_FSTAT64;
299668d75effSDimitry Andric   TSAN_INTERCEPT(open);
299768d75effSDimitry Andric   TSAN_MAYBE_INTERCEPT_OPEN64;
299868d75effSDimitry Andric   TSAN_INTERCEPT(creat);
299968d75effSDimitry Andric   TSAN_MAYBE_INTERCEPT_CREAT64;
300068d75effSDimitry Andric   TSAN_INTERCEPT(dup);
300168d75effSDimitry Andric   TSAN_INTERCEPT(dup2);
300268d75effSDimitry Andric   TSAN_INTERCEPT(dup3);
300368d75effSDimitry Andric   TSAN_MAYBE_INTERCEPT_EVENTFD;
300468d75effSDimitry Andric   TSAN_MAYBE_INTERCEPT_SIGNALFD;
300568d75effSDimitry Andric   TSAN_MAYBE_INTERCEPT_INOTIFY_INIT;
300668d75effSDimitry Andric   TSAN_MAYBE_INTERCEPT_INOTIFY_INIT1;
300768d75effSDimitry Andric   TSAN_INTERCEPT(socket);
300868d75effSDimitry Andric   TSAN_INTERCEPT(socketpair);
300968d75effSDimitry Andric   TSAN_INTERCEPT(connect);
301068d75effSDimitry Andric   TSAN_INTERCEPT(bind);
301168d75effSDimitry Andric   TSAN_INTERCEPT(listen);
301268d75effSDimitry Andric   TSAN_MAYBE_INTERCEPT_EPOLL;
301368d75effSDimitry Andric   TSAN_INTERCEPT(close);
301468d75effSDimitry Andric   TSAN_MAYBE_INTERCEPT___CLOSE;
301568d75effSDimitry Andric   TSAN_MAYBE_INTERCEPT___RES_ICLOSE;
301668d75effSDimitry Andric   TSAN_INTERCEPT(pipe);
301768d75effSDimitry Andric   TSAN_INTERCEPT(pipe2);
301868d75effSDimitry Andric 
301968d75effSDimitry Andric   TSAN_INTERCEPT(unlink);
302068d75effSDimitry Andric   TSAN_INTERCEPT(tmpfile);
302168d75effSDimitry Andric   TSAN_MAYBE_INTERCEPT_TMPFILE64;
302268d75effSDimitry Andric   TSAN_INTERCEPT(abort);
302368d75effSDimitry Andric   TSAN_INTERCEPT(rmdir);
302468d75effSDimitry Andric   TSAN_INTERCEPT(closedir);
302568d75effSDimitry Andric 
302668d75effSDimitry Andric   TSAN_INTERCEPT(sigsuspend);
302768d75effSDimitry Andric   TSAN_INTERCEPT(sigblock);
302868d75effSDimitry Andric   TSAN_INTERCEPT(sigsetmask);
302968d75effSDimitry Andric   TSAN_INTERCEPT(pthread_sigmask);
303068d75effSDimitry Andric   TSAN_INTERCEPT(raise);
303168d75effSDimitry Andric   TSAN_INTERCEPT(kill);
303268d75effSDimitry Andric   TSAN_INTERCEPT(pthread_kill);
303368d75effSDimitry Andric   TSAN_INTERCEPT(sleep);
303468d75effSDimitry Andric   TSAN_INTERCEPT(usleep);
303568d75effSDimitry Andric   TSAN_INTERCEPT(nanosleep);
303668d75effSDimitry Andric   TSAN_INTERCEPT(pause);
303768d75effSDimitry Andric   TSAN_INTERCEPT(gettimeofday);
303868d75effSDimitry Andric   TSAN_INTERCEPT(getaddrinfo);
303968d75effSDimitry Andric 
304068d75effSDimitry Andric   TSAN_INTERCEPT(fork);
304168d75effSDimitry Andric   TSAN_INTERCEPT(vfork);
3042349cc55cSDimitry Andric #if SANITIZER_LINUX
3043349cc55cSDimitry Andric   TSAN_INTERCEPT(clone);
3044349cc55cSDimitry Andric #endif
304568d75effSDimitry Andric #if !SANITIZER_ANDROID
304668d75effSDimitry Andric   TSAN_INTERCEPT(dl_iterate_phdr);
304768d75effSDimitry Andric #endif
304868d75effSDimitry Andric   TSAN_MAYBE_INTERCEPT_ON_EXIT;
304968d75effSDimitry Andric   TSAN_INTERCEPT(__cxa_atexit);
305068d75effSDimitry Andric   TSAN_INTERCEPT(_exit);
305168d75effSDimitry Andric 
305268d75effSDimitry Andric   TSAN_MAYBE_INTERCEPT__LWP_EXIT;
305368d75effSDimitry Andric   TSAN_MAYBE_INTERCEPT_THR_EXIT;
305468d75effSDimitry Andric 
305581ad6265SDimitry Andric #if !SANITIZER_APPLE && !SANITIZER_ANDROID
305668d75effSDimitry Andric   // Need to setup it, because interceptors check that the function is resolved.
305768d75effSDimitry Andric   // But atexit is emitted directly into the module, so can't be resolved.
305868d75effSDimitry Andric   REAL(atexit) = (int(*)(void(*)()))unreachable;
305968d75effSDimitry Andric #endif
306068d75effSDimitry Andric 
306168d75effSDimitry Andric   if (REAL(__cxa_atexit)(&finalize, 0, 0)) {
306268d75effSDimitry Andric     Printf("ThreadSanitizer: failed to setup atexit callback\n");
306368d75effSDimitry Andric     Die();
306468d75effSDimitry Andric   }
3065fe6060f1SDimitry Andric   if (pthread_atfork(atfork_prepare, atfork_parent, atfork_child)) {
3066fe6060f1SDimitry Andric     Printf("ThreadSanitizer: failed to setup atfork callbacks\n");
3067fe6060f1SDimitry Andric     Die();
3068fe6060f1SDimitry Andric   }
306968d75effSDimitry Andric 
307081ad6265SDimitry Andric #if !SANITIZER_APPLE && !SANITIZER_NETBSD && !SANITIZER_FREEBSD
307168d75effSDimitry Andric   if (pthread_key_create(&interceptor_ctx()->finalize_key, &thread_finalize)) {
307268d75effSDimitry Andric     Printf("ThreadSanitizer: failed to create thread key\n");
307368d75effSDimitry Andric     Die();
307468d75effSDimitry Andric   }
307568d75effSDimitry Andric #endif
307668d75effSDimitry Andric 
30771c21bfb1SDimitry Andric   TSAN_MAYBE_INTERCEPT_FREEBSD_ALIAS(cond_init);
30781c21bfb1SDimitry Andric   TSAN_MAYBE_INTERCEPT_FREEBSD_ALIAS(cond_destroy);
30791c21bfb1SDimitry Andric   TSAN_MAYBE_INTERCEPT_FREEBSD_ALIAS(cond_signal);
30801c21bfb1SDimitry Andric   TSAN_MAYBE_INTERCEPT_FREEBSD_ALIAS(cond_broadcast);
30811c21bfb1SDimitry Andric   TSAN_MAYBE_INTERCEPT_FREEBSD_ALIAS(cond_wait);
30821c21bfb1SDimitry Andric   TSAN_MAYBE_INTERCEPT_FREEBSD_ALIAS(mutex_init);
30831c21bfb1SDimitry Andric   TSAN_MAYBE_INTERCEPT_FREEBSD_ALIAS(mutex_destroy);
30841c21bfb1SDimitry Andric   TSAN_MAYBE_INTERCEPT_FREEBSD_ALIAS(mutex_lock);
30851c21bfb1SDimitry Andric   TSAN_MAYBE_INTERCEPT_FREEBSD_ALIAS(mutex_trylock);
30861c21bfb1SDimitry Andric   TSAN_MAYBE_INTERCEPT_FREEBSD_ALIAS(mutex_unlock);
30871c21bfb1SDimitry Andric   TSAN_MAYBE_INTERCEPT_FREEBSD_ALIAS(rwlock_init);
30881c21bfb1SDimitry Andric   TSAN_MAYBE_INTERCEPT_FREEBSD_ALIAS(rwlock_destroy);
30891c21bfb1SDimitry Andric   TSAN_MAYBE_INTERCEPT_FREEBSD_ALIAS(rwlock_rdlock);
30901c21bfb1SDimitry Andric   TSAN_MAYBE_INTERCEPT_FREEBSD_ALIAS(rwlock_tryrdlock);
30911c21bfb1SDimitry Andric   TSAN_MAYBE_INTERCEPT_FREEBSD_ALIAS(rwlock_wrlock);
30921c21bfb1SDimitry Andric   TSAN_MAYBE_INTERCEPT_FREEBSD_ALIAS(rwlock_trywrlock);
30931c21bfb1SDimitry Andric   TSAN_MAYBE_INTERCEPT_FREEBSD_ALIAS(rwlock_unlock);
30941c21bfb1SDimitry Andric   TSAN_MAYBE_INTERCEPT_FREEBSD_ALIAS(once);
30951c21bfb1SDimitry Andric   TSAN_MAYBE_INTERCEPT_FREEBSD_ALIAS(sigmask);
30961c21bfb1SDimitry Andric 
309768d75effSDimitry Andric   TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(cond_init);
309868d75effSDimitry Andric   TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(cond_signal);
309968d75effSDimitry Andric   TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(cond_broadcast);
310068d75effSDimitry Andric   TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(cond_wait);
310168d75effSDimitry Andric   TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(cond_destroy);
310268d75effSDimitry Andric   TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(mutex_init);
310368d75effSDimitry Andric   TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(mutex_destroy);
3104bdd1243dSDimitry Andric   TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(mutex_lock);
310568d75effSDimitry Andric   TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(mutex_trylock);
3106bdd1243dSDimitry Andric   TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(mutex_unlock);
310768d75effSDimitry Andric   TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(rwlock_init);
310868d75effSDimitry Andric   TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(rwlock_destroy);
310968d75effSDimitry Andric   TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(rwlock_rdlock);
311068d75effSDimitry Andric   TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(rwlock_tryrdlock);
311168d75effSDimitry Andric   TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(rwlock_wrlock);
311268d75effSDimitry Andric   TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(rwlock_trywrlock);
311368d75effSDimitry Andric   TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(rwlock_unlock);
311468d75effSDimitry Andric   TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS_THR(once);
311568d75effSDimitry Andric   TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS_THR(sigsetmask);
311668d75effSDimitry Andric 
311768d75effSDimitry Andric   FdInit();
311868d75effSDimitry Andric }
311968d75effSDimitry Andric 
312068d75effSDimitry Andric }  // namespace __tsan
312168d75effSDimitry Andric 
312268d75effSDimitry Andric // Invisible barrier for tests.
312368d75effSDimitry Andric // There were several unsuccessful iterations for this functionality:
312468d75effSDimitry Andric // 1. Initially it was implemented in user code using
312568d75effSDimitry Andric //    REAL(pthread_barrier_wait). But pthread_barrier_wait is not supported on
312668d75effSDimitry Andric //    MacOS. Futexes are linux-specific for this matter.
312768d75effSDimitry Andric // 2. Then we switched to atomics+usleep(10). But usleep produced parasitic
312868d75effSDimitry Andric //    "as-if synchronized via sleep" messages in reports which failed some
312968d75effSDimitry Andric //    output tests.
313068d75effSDimitry Andric // 3. Then we switched to atomics+sched_yield. But this produced tons of tsan-
313168d75effSDimitry Andric //    visible events, which lead to "failed to restore stack trace" failures.
313268d75effSDimitry Andric // Note that no_sanitize_thread attribute does not turn off atomic interception
313368d75effSDimitry Andric // so attaching it to the function defined in user code does not help.
313468d75effSDimitry Andric // That's why we now have what we have.
3135349cc55cSDimitry Andric constexpr u32 kBarrierThreadBits = 10;
3136349cc55cSDimitry Andric constexpr u32 kBarrierThreads = 1 << kBarrierThreadBits;
3137349cc55cSDimitry Andric 
3138bdd1243dSDimitry Andric extern "C" {
3139bdd1243dSDimitry Andric 
3140bdd1243dSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void __tsan_testonly_barrier_init(
3141349cc55cSDimitry Andric     atomic_uint32_t *barrier, u32 num_threads) {
3142349cc55cSDimitry Andric   if (num_threads >= kBarrierThreads) {
3143349cc55cSDimitry Andric     Printf("barrier_init: count is too large (%d)\n", num_threads);
314468d75effSDimitry Andric     Die();
314568d75effSDimitry Andric   }
3146349cc55cSDimitry Andric   // kBarrierThreadBits lsb is thread count,
3147349cc55cSDimitry Andric   // the remaining are count of entered threads.
3148349cc55cSDimitry Andric   atomic_store(barrier, num_threads, memory_order_relaxed);
314968d75effSDimitry Andric }
315068d75effSDimitry Andric 
3151349cc55cSDimitry Andric static u32 barrier_epoch(u32 value) {
3152349cc55cSDimitry Andric   return (value >> kBarrierThreadBits) / (value & (kBarrierThreads - 1));
3153349cc55cSDimitry Andric }
3154349cc55cSDimitry Andric 
3155bdd1243dSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void __tsan_testonly_barrier_wait(
3156349cc55cSDimitry Andric     atomic_uint32_t *barrier) {
3157349cc55cSDimitry Andric   u32 old = atomic_fetch_add(barrier, kBarrierThreads, memory_order_relaxed);
3158349cc55cSDimitry Andric   u32 old_epoch = barrier_epoch(old);
3159349cc55cSDimitry Andric   if (barrier_epoch(old + kBarrierThreads) != old_epoch) {
3160349cc55cSDimitry Andric     FutexWake(barrier, (1 << 30));
316168d75effSDimitry Andric     return;
3162349cc55cSDimitry Andric   }
3163349cc55cSDimitry Andric   for (;;) {
3164349cc55cSDimitry Andric     u32 cur = atomic_load(barrier, memory_order_relaxed);
3165349cc55cSDimitry Andric     if (barrier_epoch(cur) != old_epoch)
3166349cc55cSDimitry Andric       return;
3167349cc55cSDimitry Andric     FutexWait(barrier, cur);
316868d75effSDimitry Andric   }
316968d75effSDimitry Andric }
3170bdd1243dSDimitry Andric 
317106c3fb27SDimitry Andric }  // extern "C"
3172