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