diff options
Diffstat (limited to 'libsanitizer/tsan')
30 files changed, 1115 insertions, 586 deletions
diff --git a/libsanitizer/tsan/tsan_debugging.cc b/libsanitizer/tsan/tsan_debugging.cc index 9a9c67f..722b6c1 100644 --- a/libsanitizer/tsan/tsan_debugging.cc +++ b/libsanitizer/tsan/tsan_debugging.cc @@ -81,6 +81,13 @@ int __tsan_get_report_data(void *report, const char **description, int *count, } SANITIZER_INTERFACE_ATTRIBUTE +int __tsan_get_report_tag(void *report, uptr *tag) { + const ReportDesc *rep = (ReportDesc *)report; + *tag = rep->tag; + return 1; +} + +SANITIZER_INTERFACE_ATTRIBUTE int __tsan_get_report_stack(void *report, uptr idx, void **trace, uptr trace_size) { const ReportDesc *rep = (ReportDesc *)report; diff --git a/libsanitizer/tsan/tsan_interceptors.cc b/libsanitizer/tsan/tsan_interceptors.cc index 15f20d4..069df59 100644 --- a/libsanitizer/tsan/tsan_interceptors.cc +++ b/libsanitizer/tsan/tsan_interceptors.cc @@ -41,8 +41,16 @@ using namespace __tsan; // NOLINT #if SANITIZER_NETBSD #define dirfd(dirp) (*(int *)(dirp)) #define fileno_unlocked fileno -#define stdout __sF[1] -#define stderr __sF[2] + +#if _LP64 +#define __sF_size 152 +#else +#define __sF_size 88 +#endif + +#define stdout ((char*)&__sF + (__sF_size * 1)) +#define stderr ((char*)&__sF + (__sF_size * 2)) + #endif #if SANITIZER_ANDROID @@ -55,11 +63,6 @@ const int kSigCount = 129; const int kSigCount = 65; #endif -struct my_siginfo_t { - // The size is determined by looking at sizeof of real siginfo_t on linux. - u64 opaque[128 / sizeof(u64)]; -}; - #ifdef __mips__ struct ucontext_t { u64 opaque[768 / sizeof(u64) + 1]; @@ -97,7 +100,7 @@ extern "C" int dirfd(void *dirp); extern "C" int mallopt(int param, int value); #endif #if SANITIZER_NETBSD -extern __sanitizer_FILE **__sF; +extern __sanitizer_FILE __sF[]; #else extern __sanitizer_FILE *stdout, *stderr; #endif @@ -139,56 +142,6 @@ typedef long long_t; // NOLINT # define F_TLOCK 2 /* Test and lock a region for exclusive use. */ # define F_TEST 3 /* Test a region for other processes locks. */ -typedef void (*sighandler_t)(int sig); -typedef void (*sigactionhandler_t)(int sig, my_siginfo_t *siginfo, void *uctx); - -#if SANITIZER_ANDROID -struct sigaction_t { - u32 sa_flags; - union { - sighandler_t sa_handler; - sigactionhandler_t sa_sigaction; - }; - __sanitizer_sigset_t sa_mask; - void (*sa_restorer)(); -}; -#elif SANITIZER_NETBSD -struct sigaction_t { - union { - sighandler_t sa_handler; - sigactionhandler_t sa_sigaction; - }; - __sanitizer_sigset_t sa_mask; - int sa_flags; -}; -#else -struct sigaction_t { -#ifdef __mips__ - u32 sa_flags; -#endif - union { - sighandler_t sa_handler; - sigactionhandler_t sa_sigaction; - }; -#if SANITIZER_FREEBSD - int sa_flags; - __sanitizer_sigset_t sa_mask; -#elif SANITIZER_MAC - __sanitizer_sigset_t sa_mask; - int sa_flags; -#else - __sanitizer_sigset_t sa_mask; -#ifndef __mips__ - int sa_flags; -#endif - void (*sa_restorer)(); -#endif -}; -#endif - -const sighandler_t SIG_DFL = (sighandler_t)0; -const sighandler_t SIG_IGN = (sighandler_t)1; -const sighandler_t SIG_ERR = (sighandler_t)-1; #if SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_NETBSD const int SA_SIGINFO = 0x40; const int SIG_SETMASK = 3; @@ -203,13 +156,11 @@ const int SIG_SETMASK = 2; #define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED \ (!cur_thread()->is_inited) -static sigaction_t sigactions[kSigCount]; - namespace __tsan { struct SignalDesc { bool armed; bool sigaction; - my_siginfo_t siginfo; + __sanitizer_siginfo siginfo; ucontext_t ctx; }; @@ -223,11 +174,41 @@ struct ThreadSignalContext { __sanitizer_sigset_t oldset; }; -// The object is 64-byte aligned, because we want hot data to be located in -// a single cache line if possible (it's accessed in every interceptor). -static ALIGNED(64) char libignore_placeholder[sizeof(LibIgnore)]; +// The sole reason tsan wraps atexit callbacks is to establish synchronization +// between callback setup and callback execution. +struct AtExitCtx { + void (*f)(); + void *arg; +}; + +// InterceptorContext holds all global data required for interceptors. +// It's explicitly constructed in InitializeInterceptors with placement new +// and is never destroyed. This allows usage of members with non-trivial +// constructors and destructors. +struct InterceptorContext { + // The object is 64-byte aligned, because we want hot data to be located + // in a single cache line if possible (it's accessed in every interceptor). + ALIGNED(64) LibIgnore libignore; + __sanitizer_sigaction sigactions[kSigCount]; +#if !SANITIZER_MAC && !SANITIZER_NETBSD + unsigned finalize_key; +#endif + + BlockingMutex atexit_mu; + Vector<struct AtExitCtx *> AtExitStack; + + InterceptorContext() + : libignore(LINKER_INITIALIZED), AtExitStack() { + } +}; + +static ALIGNED(64) char interceptor_placeholder[sizeof(InterceptorContext)]; +InterceptorContext *interceptor_ctx() { + return reinterpret_cast<InterceptorContext*>(&interceptor_placeholder[0]); +} + LibIgnore *libignore() { - return reinterpret_cast<LibIgnore*>(&libignore_placeholder[0]); + return &interceptor_ctx()->libignore; } void InitializeLibIgnore() { @@ -255,10 +236,6 @@ static ThreadSignalContext *SigCtx(ThreadState *thr) { return ctx; } -#if !SANITIZER_MAC -static unsigned g_thread_finalize_key; -#endif - ScopedInterceptor::ScopedInterceptor(ThreadState *thr, const char *fname, uptr pc) : thr_(thr), pc_(pc), in_ignored_lib_(false), ignoring_(false) { @@ -305,10 +282,20 @@ void ScopedInterceptor::DisableIgnores() { } #define TSAN_INTERCEPT(func) INTERCEPT_FUNCTION(func) -#if SANITIZER_FREEBSD || SANITIZER_NETBSD +#if SANITIZER_FREEBSD # define TSAN_INTERCEPT_VER(func, ver) INTERCEPT_FUNCTION(func) +# define TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(func) +# define TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS_THR(func) +#elif SANITIZER_NETBSD +# define TSAN_INTERCEPT_VER(func, ver) INTERCEPT_FUNCTION(func) +# define TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(func) \ + INTERCEPT_FUNCTION(__libc_##func) +# define TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS_THR(func) \ + INTERCEPT_FUNCTION(__libc_thr_##func) #else # define TSAN_INTERCEPT_VER(func, ver) INTERCEPT_FUNCTION_VER(func, ver) +# define TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(func) +# define TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS_THR(func) #endif #define READ_STRING_OF_LEN(thr, pc, s, len, n) \ @@ -369,22 +356,30 @@ TSAN_INTERCEPTOR(int, nanosleep, void *req, void *rem) { return res; } -TSAN_INTERCEPTOR(int, pause) { - SCOPED_TSAN_INTERCEPTOR(pause); - return BLOCK_REAL(pause)(); +TSAN_INTERCEPTOR(int, pause, int fake) { + SCOPED_TSAN_INTERCEPTOR(pause, fake); + return BLOCK_REAL(pause)(fake); } -// The sole reason tsan wraps atexit callbacks is to establish synchronization -// between callback setup and callback execution. -struct AtExitCtx { - void (*f)(); - void *arg; -}; +static void at_exit_wrapper() { + AtExitCtx *ctx; + { + // Ensure thread-safety. + BlockingMutexLock l(&interceptor_ctx()->atexit_mu); -static void at_exit_wrapper(void *arg) { - ThreadState *thr = cur_thread(); - uptr pc = 0; - Acquire(thr, pc, (uptr)arg); + // Pop AtExitCtx from the top of the stack of callback functions + uptr element = interceptor_ctx()->AtExitStack.Size() - 1; + ctx = interceptor_ctx()->AtExitStack[element]; + interceptor_ctx()->AtExitStack.PopBack(); + } + + Acquire(cur_thread(), (uptr)0, (uptr)ctx); + ((void(*)())ctx->f)(); + InternalFree(ctx); +} + +static void cxa_at_exit_wrapper(void *arg) { + Acquire(cur_thread(), 0, (uptr)arg); AtExitCtx *ctx = (AtExitCtx*)arg; ((void(*)(void *arg))ctx->f)(ctx->arg); InternalFree(ctx); @@ -395,7 +390,7 @@ static int setup_at_exit_wrapper(ThreadState *thr, uptr pc, void(*f)(), #if !SANITIZER_ANDROID TSAN_INTERCEPTOR(int, atexit, void (*f)()) { - if (cur_thread()->in_symbolizer) + if (UNLIKELY(cur_thread()->in_symbolizer)) return 0; // We want to setup the atexit callback even if we are in ignored lib // or after fork. @@ -405,7 +400,7 @@ TSAN_INTERCEPTOR(int, atexit, void (*f)()) { #endif TSAN_INTERCEPTOR(int, __cxa_atexit, void (*f)(void *a), void *arg, void *dso) { - if (cur_thread()->in_symbolizer) + if (UNLIKELY(cur_thread()->in_symbolizer)) return 0; SCOPED_TSAN_INTERCEPTOR(__cxa_atexit, f, arg, dso); return setup_at_exit_wrapper(thr, pc, (void(*)())f, arg, dso); @@ -420,12 +415,27 @@ static int setup_at_exit_wrapper(ThreadState *thr, uptr pc, void(*f)(), // Memory allocation in __cxa_atexit will race with free during exit, // because we do not see synchronization around atexit callback list. ThreadIgnoreBegin(thr, pc); - int res = REAL(__cxa_atexit)(at_exit_wrapper, ctx, dso); + int res; + if (!dso) { + // NetBSD does not preserve the 2nd argument if dso is equal to 0 + // Store ctx in a local stack-like structure + + // Ensure thread-safety. + BlockingMutexLock l(&interceptor_ctx()->atexit_mu); + + res = REAL(__cxa_atexit)((void (*)(void *a))at_exit_wrapper, 0, 0); + // Push AtExitCtx on the top of the stack of callback functions + if (!res) { + interceptor_ctx()->AtExitStack.PushBack(ctx); + } + } else { + res = REAL(__cxa_atexit)(cxa_at_exit_wrapper, ctx, dso); + } ThreadIgnoreEnd(thr, pc); return res; } -#if !SANITIZER_MAC +#if !SANITIZER_MAC && !SANITIZER_NETBSD static void on_exit_wrapper(int status, void *arg) { ThreadState *thr = cur_thread(); uptr pc = 0; @@ -436,7 +446,7 @@ static void on_exit_wrapper(int status, void *arg) { } TSAN_INTERCEPTOR(int, on_exit, void(*f)(int, void*), void *arg) { - if (cur_thread()->in_symbolizer) + if (UNLIKELY(cur_thread()->in_symbolizer)) return 0; SCOPED_TSAN_INTERCEPTOR(on_exit, f, arg); AtExitCtx *ctx = (AtExitCtx*)InternalAlloc(sizeof(AtExitCtx)); @@ -450,6 +460,9 @@ TSAN_INTERCEPTOR(int, on_exit, void(*f)(int, void*), void *arg) { ThreadIgnoreEnd(thr, pc); return res; } +#define TSAN_MAYBE_INTERCEPT_ON_EXIT TSAN_INTERCEPT(on_exit) +#else +#define TSAN_MAYBE_INTERCEPT_ON_EXIT #endif // Cleanup old bufs. @@ -487,15 +500,18 @@ static void SetJmp(ThreadState *thr, uptr sp, uptr mangled_sp) { static void LongJmp(ThreadState *thr, uptr *env) { #ifdef __powerpc__ uptr mangled_sp = env[0]; -#elif SANITIZER_FREEBSD || SANITIZER_NETBSD +#elif SANITIZER_FREEBSD uptr mangled_sp = env[2]; +#elif SANITIZER_NETBSD + uptr mangled_sp = env[6]; #elif SANITIZER_MAC # ifdef __aarch64__ - uptr mangled_sp = env[13]; + uptr mangled_sp = + (GetMacosVersion() >= MACOS_VERSION_MOJAVE) ? env[12] : env[13]; # else uptr mangled_sp = env[2]; # endif -#elif defined(SANITIZER_LINUX) +#elif SANITIZER_LINUX # ifdef __aarch64__ uptr mangled_sp = env[13]; # elif defined(__mips64) @@ -538,10 +554,27 @@ TSAN_INTERCEPTOR(int, setjmp, void *env); TSAN_INTERCEPTOR(int, _setjmp, void *env); TSAN_INTERCEPTOR(int, sigsetjmp, void *env); #else // SANITIZER_MAC + +#if SANITIZER_NETBSD +#define setjmp_symname __setjmp14 +#define sigsetjmp_symname __sigsetjmp14 +#else +#define setjmp_symname setjmp +#define sigsetjmp_symname sigsetjmp +#endif + +#define TSAN_INTERCEPTOR_SETJMP_(x) __interceptor_ ## x +#define TSAN_INTERCEPTOR_SETJMP__(x) TSAN_INTERCEPTOR_SETJMP_(x) +#define TSAN_INTERCEPTOR_SETJMP TSAN_INTERCEPTOR_SETJMP__(setjmp_symname) +#define TSAN_INTERCEPTOR_SIGSETJMP TSAN_INTERCEPTOR_SETJMP__(sigsetjmp_symname) + +#define TSAN_STRING_SETJMP SANITIZER_STRINGIFY(setjmp_symname) +#define TSAN_STRING_SIGSETJMP SANITIZER_STRINGIFY(sigsetjmp_symname) + // Not called. Merely to satisfy TSAN_INTERCEPT(). extern "C" SANITIZER_INTERFACE_ATTRIBUTE -int __interceptor_setjmp(void *env); -extern "C" int __interceptor_setjmp(void *env) { +int TSAN_INTERCEPTOR_SETJMP(void *env); +extern "C" int TSAN_INTERCEPTOR_SETJMP(void *env) { CHECK(0); return 0; } @@ -555,51 +588,75 @@ extern "C" int __interceptor__setjmp(void *env) { } extern "C" SANITIZER_INTERFACE_ATTRIBUTE -int __interceptor_sigsetjmp(void *env); -extern "C" int __interceptor_sigsetjmp(void *env) { +int TSAN_INTERCEPTOR_SIGSETJMP(void *env); +extern "C" int TSAN_INTERCEPTOR_SIGSETJMP(void *env) { CHECK(0); return 0; } +#if !SANITIZER_NETBSD extern "C" SANITIZER_INTERFACE_ATTRIBUTE int __interceptor___sigsetjmp(void *env); extern "C" int __interceptor___sigsetjmp(void *env) { CHECK(0); return 0; } +#endif -extern "C" int setjmp(void *env); +extern "C" int setjmp_symname(void *env); extern "C" int _setjmp(void *env); -extern "C" int sigsetjmp(void *env); +extern "C" int sigsetjmp_symname(void *env); +#if !SANITIZER_NETBSD extern "C" int __sigsetjmp(void *env); -DEFINE_REAL(int, setjmp, void *env) +#endif +DEFINE_REAL(int, setjmp_symname, void *env) DEFINE_REAL(int, _setjmp, void *env) -DEFINE_REAL(int, sigsetjmp, void *env) +DEFINE_REAL(int, sigsetjmp_symname, void *env) +#if !SANITIZER_NETBSD DEFINE_REAL(int, __sigsetjmp, void *env) +#endif #endif // SANITIZER_MAC -TSAN_INTERCEPTOR(void, longjmp, uptr *env, int val) { +#if SANITIZER_NETBSD +#define longjmp_symname __longjmp14 +#define siglongjmp_symname __siglongjmp14 +#else +#define longjmp_symname longjmp +#define siglongjmp_symname siglongjmp +#endif + +TSAN_INTERCEPTOR(void, longjmp_symname, uptr *env, int val) { // Note: if we call REAL(longjmp) in the context of ScopedInterceptor, // bad things will happen. We will jump over ScopedInterceptor dtor and can // leave thr->in_ignored_lib set. { - SCOPED_INTERCEPTOR_RAW(longjmp, env, val); + SCOPED_INTERCEPTOR_RAW(longjmp_symname, env, val); + } + LongJmp(cur_thread(), env); + REAL(longjmp_symname)(env, val); +} + +TSAN_INTERCEPTOR(void, siglongjmp_symname, uptr *env, int val) { + { + SCOPED_INTERCEPTOR_RAW(siglongjmp_symname, env, val); } LongJmp(cur_thread(), env); - REAL(longjmp)(env, val); + REAL(siglongjmp_symname)(env, val); } -TSAN_INTERCEPTOR(void, siglongjmp, uptr *env, int val) { +#if SANITIZER_NETBSD +TSAN_INTERCEPTOR(void, _longjmp, uptr *env, int val) { { - SCOPED_INTERCEPTOR_RAW(siglongjmp, env, val); + SCOPED_INTERCEPTOR_RAW(_longjmp, env, val); } LongJmp(cur_thread(), env); - REAL(siglongjmp)(env, val); + REAL(_longjmp)(env, val); } +#endif #if !SANITIZER_MAC TSAN_INTERCEPTOR(void*, malloc, uptr size) { - if (cur_thread()->in_symbolizer) + if (UNLIKELY(cur_thread()->in_symbolizer)) return InternalAlloc(size); void *p = 0; { @@ -616,7 +673,7 @@ TSAN_INTERCEPTOR(void*, __libc_memalign, uptr align, uptr sz) { } TSAN_INTERCEPTOR(void*, calloc, uptr size, uptr n) { - if (cur_thread()->in_symbolizer) + if (UNLIKELY(cur_thread()->in_symbolizer)) return InternalCalloc(size, n); void *p = 0; { @@ -628,7 +685,7 @@ TSAN_INTERCEPTOR(void*, calloc, uptr size, uptr n) { } TSAN_INTERCEPTOR(void*, realloc, void *p, uptr size) { - if (cur_thread()->in_symbolizer) + if (UNLIKELY(cur_thread()->in_symbolizer)) return InternalRealloc(p, size); if (p) invoke_free_hook(p); @@ -643,7 +700,7 @@ TSAN_INTERCEPTOR(void*, realloc, void *p, uptr size) { TSAN_INTERCEPTOR(void, free, void *p) { if (p == 0) return; - if (cur_thread()->in_symbolizer) + if (UNLIKELY(cur_thread()->in_symbolizer)) return InternalFree(p); invoke_free_hook(p); SCOPED_INTERCEPTOR_RAW(free, p); @@ -653,7 +710,7 @@ TSAN_INTERCEPTOR(void, free, void *p) { TSAN_INTERCEPTOR(void, cfree, void *p) { if (p == 0) return; - if (cur_thread()->in_symbolizer) + if (UNLIKELY(cur_thread()->in_symbolizer)) return InternalFree(p); invoke_free_hook(p); SCOPED_INTERCEPTOR_RAW(cfree, p); @@ -702,35 +759,14 @@ static bool fix_mmap_addr(void **addr, long_t sz, int flags) { return true; } -TSAN_INTERCEPTOR(void *, mmap, void *addr, SIZE_T sz, int prot, int flags, - int fd, OFF_T off) { - SCOPED_TSAN_INTERCEPTOR(mmap, addr, sz, prot, flags, fd, off); - if (!fix_mmap_addr(&addr, sz, flags)) - return MAP_FAILED; - void *res = REAL(mmap)(addr, sz, prot, flags, fd, off); - if (res != MAP_FAILED) { - if (fd > 0) - FdAccess(thr, pc, fd); - - if (thr->ignore_reads_and_writes == 0) - MemoryRangeImitateWrite(thr, pc, (uptr)res, sz); - else - MemoryResetRange(thr, pc, (uptr)res, sz); - } - return res; -} - -#if SANITIZER_LINUX -TSAN_INTERCEPTOR(void *, mmap64, void *addr, SIZE_T sz, int prot, int flags, - int fd, OFF64_T off) { - SCOPED_TSAN_INTERCEPTOR(mmap64, addr, sz, prot, flags, fd, off); - if (!fix_mmap_addr(&addr, sz, flags)) - return MAP_FAILED; - void *res = REAL(mmap64)(addr, sz, prot, flags, fd, off); +template <class Mmap> +static void *mmap_interceptor(ThreadState *thr, uptr pc, Mmap real_mmap, + void *addr, SIZE_T sz, int prot, int flags, + int fd, OFF64_T off) { + if (!fix_mmap_addr(&addr, sz, flags)) return MAP_FAILED; + void *res = real_mmap(addr, sz, prot, flags, fd, off); if (res != MAP_FAILED) { - if (fd > 0) - FdAccess(thr, pc, fd); - + if (fd > 0) FdAccess(thr, pc, fd); if (thr->ignore_reads_and_writes == 0) MemoryRangeImitateWrite(thr, pc, (uptr)res, sz); else @@ -738,10 +774,6 @@ TSAN_INTERCEPTOR(void *, mmap64, void *addr, SIZE_T sz, int prot, int flags, } return res; } -#define TSAN_MAYBE_INTERCEPT_MMAP64 TSAN_INTERCEPT(mmap64) -#else -#define TSAN_MAYBE_INTERCEPT_MMAP64 -#endif TSAN_INTERCEPTOR(int, munmap, void *addr, long_t sz) { SCOPED_TSAN_INTERCEPTOR(munmap, addr, sz); @@ -767,11 +799,15 @@ TSAN_INTERCEPTOR(void*, memalign, uptr align, uptr sz) { #if !SANITIZER_MAC TSAN_INTERCEPTOR(void*, aligned_alloc, uptr align, uptr sz) { + if (UNLIKELY(cur_thread()->in_symbolizer)) + return InternalAlloc(sz, nullptr, align); SCOPED_INTERCEPTOR_RAW(aligned_alloc, align, sz); return user_aligned_alloc(thr, pc, align, sz); } TSAN_INTERCEPTOR(void*, valloc, uptr sz) { + if (UNLIKELY(cur_thread()->in_symbolizer)) + return InternalAlloc(sz, nullptr, GetPageSizeCached()); SCOPED_INTERCEPTOR_RAW(valloc, sz); return user_valloc(thr, pc, sz); } @@ -779,6 +815,11 @@ TSAN_INTERCEPTOR(void*, valloc, uptr sz) { #if SANITIZER_LINUX TSAN_INTERCEPTOR(void*, pvalloc, uptr sz) { + if (UNLIKELY(cur_thread()->in_symbolizer)) { + uptr PageSize = GetPageSizeCached(); + sz = sz ? RoundUpTo(sz, PageSize) : PageSize; + return InternalAlloc(sz, nullptr, PageSize); + } SCOPED_INTERCEPTOR_RAW(pvalloc, sz); return user_pvalloc(thr, pc, sz); } @@ -789,6 +830,13 @@ TSAN_INTERCEPTOR(void*, pvalloc, uptr sz) { #if !SANITIZER_MAC TSAN_INTERCEPTOR(int, posix_memalign, void **memptr, uptr align, uptr sz) { + if (UNLIKELY(cur_thread()->in_symbolizer)) { + void *p = InternalAlloc(sz, nullptr, align); + if (!p) + return errno_ENOMEM; + *memptr = p; + return 0; + } SCOPED_INTERCEPTOR_RAW(posix_memalign, memptr, align, sz); return user_posix_memalign(thr, pc, memptr, align, sz); } @@ -856,11 +904,12 @@ void DestroyThreadState() { } } // namespace __tsan -#if !SANITIZER_MAC +#if !SANITIZER_MAC && !SANITIZER_NETBSD && !SANITIZER_FREEBSD static void thread_finalize(void *v) { uptr iter = (uptr)v; if (iter > 1) { - if (pthread_setspecific(g_thread_finalize_key, (void*)(iter - 1))) { + if (pthread_setspecific(interceptor_ctx()->finalize_key, + (void*)(iter - 1))) { Printf("ThreadSanitizer: failed to set thread key\n"); Die(); } @@ -886,9 +935,9 @@ extern "C" void *__tsan_thread_start_func(void *arg) { ThreadState *thr = cur_thread(); // Thread-local state is not initialized yet. ScopedIgnoreInterceptors ignore; -#if !SANITIZER_MAC +#if !SANITIZER_MAC && !SANITIZER_NETBSD && !SANITIZER_FREEBSD ThreadIgnoreBegin(thr, 0); - if (pthread_setspecific(g_thread_finalize_key, + if (pthread_setspecific(interceptor_ctx()->finalize_key, (void *)GetPthreadDestructorIterations())) { Printf("ThreadSanitizer: failed to set thread key\n"); Die(); @@ -913,6 +962,9 @@ extern "C" void *__tsan_thread_start_func(void *arg) { TSAN_INTERCEPTOR(int, pthread_create, void *th, void *attr, void *(*callback)(void*), void * param) { SCOPED_INTERCEPTOR_RAW(pthread_create, th, attr, callback, param); + + MaybeSpawnBackgroundThread(); + if (ctx->after_multithreaded_fork) { if (flags()->die_after_fork) { Report("ThreadSanitizer: starting new threads after multi-threaded " @@ -1338,10 +1390,15 @@ TSAN_INTERCEPTOR(int, pthread_once, void *o, void (*f)()) { if (o == 0 || f == 0) return errno_EINVAL; atomic_uint32_t *a; - if (!SANITIZER_MAC) - a = static_cast<atomic_uint32_t*>(o); - else // On OS X, pthread_once_t has a header with a long-sized signature. + + if (SANITIZER_MAC) a = static_cast<atomic_uint32_t*>((void *)((char *)o + sizeof(long_t))); + else if (SANITIZER_NETBSD) + a = static_cast<atomic_uint32_t*> + ((void *)((char *)o + __sanitizer::pthread_mutex_t_sz)); + else + a = static_cast<atomic_uint32_t*>(o); + u32 v = atomic_load(a, memory_order_acquire); if (v == 0 && atomic_compare_exchange_strong(a, &v, 1, memory_order_relaxed)) { @@ -1678,12 +1735,6 @@ TSAN_INTERCEPTOR(void, abort, int fake) { REAL(abort)(fake); } -TSAN_INTERCEPTOR(int, puts, const char *s) { - SCOPED_TSAN_INTERCEPTOR(puts, s); - MemoryAccessRange(thr, pc, (uptr)s, internal_strlen(s), false); - return REAL(puts)(s); -} - TSAN_INTERCEPTOR(int, rmdir, char *path) { SCOPED_TSAN_INTERCEPTOR(rmdir, path); Release(thr, pc, Dir2addr(path)); @@ -1788,7 +1839,9 @@ TSAN_INTERCEPTOR(int, pthread_sigmask, int how, const __sanitizer_sigset_t *set, namespace __tsan { static void CallUserSignalHandler(ThreadState *thr, bool sync, bool acquire, - bool sigact, int sig, my_siginfo_t *info, void *uctx) { + bool sigact, int sig, + __sanitizer_siginfo *info, void *uctx) { + __sanitizer_sigaction *sigactions = interceptor_ctx()->sigactions; if (acquire) Acquire(thr, 0, (uptr)&sigactions[sig]); // Signals are generally asynchronous, so if we receive a signals when @@ -1810,14 +1863,13 @@ static void CallUserSignalHandler(ThreadState *thr, bool sync, bool acquire, // This code races with sigaction. Be careful to not read sa_sigaction twice. // Also need to remember pc for reporting before the call, // because the handler can reset it. - volatile uptr pc = sigact ? - (uptr)sigactions[sig].sa_sigaction : - (uptr)sigactions[sig].sa_handler; - if (pc != (uptr)SIG_DFL && pc != (uptr)SIG_IGN) { + volatile uptr pc = + sigact ? (uptr)sigactions[sig].sigaction : (uptr)sigactions[sig].handler; + if (pc != sig_dfl && pc != sig_ign) { if (sigact) - ((sigactionhandler_t)pc)(sig, info, uctx); + ((__sanitizer_sigactionhandler_ptr)pc)(sig, info, uctx); else - ((sighandler_t)pc)(sig); + ((__sanitizer_sighandler_ptr)pc)(sig); } if (!ctx->after_multithreaded_fork) { thr->ignore_reads_and_writes = ignore_reads_and_writes; @@ -1881,7 +1933,8 @@ static bool is_sync_signal(ThreadSignalContext *sctx, int sig) { } void ALWAYS_INLINE rtl_generic_sighandler(bool sigact, int sig, - my_siginfo_t *info, void *ctx) { + __sanitizer_siginfo *info, + void *ctx) { ThreadState *thr = cur_thread(); ThreadSignalContext *sctx = SigCtx(thr); if (sig < 0 || sig >= kSigCount) { @@ -1931,58 +1984,10 @@ static void rtl_sighandler(int sig) { rtl_generic_sighandler(false, sig, 0, 0); } -static void rtl_sigaction(int sig, my_siginfo_t *info, void *ctx) { +static void rtl_sigaction(int sig, __sanitizer_siginfo *info, void *ctx) { rtl_generic_sighandler(true, sig, info, ctx); } -TSAN_INTERCEPTOR(int, sigaction, int sig, sigaction_t *act, sigaction_t *old) { - // Note: if we call REAL(sigaction) directly for any reason without proxying - // the signal handler through rtl_sigaction, very bad things will happen. - // The handler will run synchronously and corrupt tsan per-thread state. - SCOPED_INTERCEPTOR_RAW(sigaction, sig, act, old); - if (old) - internal_memcpy(old, &sigactions[sig], sizeof(*old)); - if (act == 0) - return 0; - // Copy act into sigactions[sig]. - // Can't use struct copy, because compiler can emit call to memcpy. - // Can't use internal_memcpy, because it copies byte-by-byte, - // and signal handler reads the sa_handler concurrently. It it can read - // some bytes from old value and some bytes from new value. - // Use volatile to prevent insertion of memcpy. - sigactions[sig].sa_handler = *(volatile sighandler_t*)&act->sa_handler; - sigactions[sig].sa_flags = *(volatile int*)&act->sa_flags; - internal_memcpy(&sigactions[sig].sa_mask, &act->sa_mask, - sizeof(sigactions[sig].sa_mask)); -#if !SANITIZER_FREEBSD && !SANITIZER_MAC && !SANITIZER_NETBSD - sigactions[sig].sa_restorer = act->sa_restorer; -#endif - sigaction_t newact; - internal_memcpy(&newact, act, sizeof(newact)); - internal_sigfillset(&newact.sa_mask); - if (act->sa_handler != SIG_IGN && act->sa_handler != SIG_DFL) { - if (newact.sa_flags & SA_SIGINFO) - newact.sa_sigaction = rtl_sigaction; - else - newact.sa_handler = rtl_sighandler; - } - ReleaseStore(thr, pc, (uptr)&sigactions[sig]); - int res = REAL(sigaction)(sig, &newact, 0); - return res; -} - -TSAN_INTERCEPTOR(sighandler_t, signal, int sig, sighandler_t h) { - sigaction_t act; - act.sa_handler = h; - internal_memset(&act.sa_mask, -1, sizeof(act.sa_mask)); - act.sa_flags = 0; - sigaction_t old; - int res = sigaction(sig, &act, &old); - if (res) - return SIG_ERR; - return old.sa_handler; -} - TSAN_INTERCEPTOR(int, raise, int sig) { SCOPED_TSAN_INTERCEPTOR(raise, sig); ThreadSignalContext *sctx = SigCtx(thr); @@ -2046,7 +2051,7 @@ TSAN_INTERCEPTOR(int, getaddrinfo, void *node, void *service, } TSAN_INTERCEPTOR(int, fork, int fake) { - if (cur_thread()->in_symbolizer) + if (UNLIKELY(cur_thread()->in_symbolizer)) return REAL(fork)(fake); SCOPED_INTERCEPTOR_RAW(fork, fake); ForkBefore(thr, pc); @@ -2274,6 +2279,13 @@ static void HandleRecvmsg(ThreadState *thr, uptr pc, MutexInvalidAccess(((TsanInterceptorContext *)ctx)->thr, \ ((TsanInterceptorContext *)ctx)->pc, (uptr)m) +#define COMMON_INTERCEPTOR_MMAP_IMPL(ctx, mmap, addr, sz, prot, flags, fd, \ + off) \ + do { \ + return mmap_interceptor(thr, pc, REAL(mmap), addr, sz, prot, flags, fd, \ + off); \ + } while (false) + #if !SANITIZER_MAC #define COMMON_INTERCEPTOR_HANDLE_RECVMSG(ctx, msg) \ HandleRecvmsg(((TsanInterceptorContext *)ctx)->thr, \ @@ -2296,6 +2308,77 @@ static void HandleRecvmsg(ThreadState *thr, uptr pc, #include "sanitizer_common/sanitizer_common_interceptors.inc" +static int sigaction_impl(int sig, const __sanitizer_sigaction *act, + __sanitizer_sigaction *old); +static __sanitizer_sighandler_ptr signal_impl(int sig, + __sanitizer_sighandler_ptr h); + +#define SIGNAL_INTERCEPTOR_SIGACTION_IMPL(signo, act, oldact) \ + { return sigaction_impl(signo, act, oldact); } + +#define SIGNAL_INTERCEPTOR_SIGNAL_IMPL(func, signo, handler) \ + { return (uptr)signal_impl(signo, (__sanitizer_sighandler_ptr)handler); } + +#include "sanitizer_common/sanitizer_signal_interceptors.inc" + +int sigaction_impl(int sig, const __sanitizer_sigaction *act, + __sanitizer_sigaction *old) { + // Note: if we call REAL(sigaction) directly for any reason without proxying + // the signal handler through rtl_sigaction, very bad things will happen. + // The handler will run synchronously and corrupt tsan per-thread state. + SCOPED_INTERCEPTOR_RAW(sigaction, sig, act, old); + __sanitizer_sigaction *sigactions = interceptor_ctx()->sigactions; + __sanitizer_sigaction old_stored; + if (old) internal_memcpy(&old_stored, &sigactions[sig], sizeof(old_stored)); + __sanitizer_sigaction newact; + if (act) { + // Copy act into sigactions[sig]. + // Can't use struct copy, because compiler can emit call to memcpy. + // Can't use internal_memcpy, because it copies byte-by-byte, + // and signal handler reads the handler concurrently. It it can read + // some bytes from old value and some bytes from new value. + // Use volatile to prevent insertion of memcpy. + sigactions[sig].handler = + *(volatile __sanitizer_sighandler_ptr const *)&act->handler; + sigactions[sig].sa_flags = *(volatile int const *)&act->sa_flags; + internal_memcpy(&sigactions[sig].sa_mask, &act->sa_mask, + sizeof(sigactions[sig].sa_mask)); +#if !SANITIZER_FREEBSD && !SANITIZER_MAC && !SANITIZER_NETBSD + sigactions[sig].sa_restorer = act->sa_restorer; +#endif + internal_memcpy(&newact, act, sizeof(newact)); + internal_sigfillset(&newact.sa_mask); + if ((uptr)act->handler != sig_ign && (uptr)act->handler != sig_dfl) { + if (newact.sa_flags & SA_SIGINFO) + newact.sigaction = rtl_sigaction; + else + newact.handler = rtl_sighandler; + } + ReleaseStore(thr, pc, (uptr)&sigactions[sig]); + act = &newact; + } + int res = REAL(sigaction)(sig, act, old); + if (res == 0 && old) { + uptr cb = (uptr)old->sigaction; + if (cb == (uptr)rtl_sigaction || cb == (uptr)rtl_sighandler) { + internal_memcpy(old, &old_stored, sizeof(*old)); + } + } + return res; +} + +static __sanitizer_sighandler_ptr signal_impl(int sig, + __sanitizer_sighandler_ptr h) { + __sanitizer_sigaction act; + act.handler = h; + internal_memset(&act.sa_mask, -1, sizeof(act.sa_mask)); + act.sa_flags = 0; + __sanitizer_sigaction old; + int res = sigaction_symname(sig, &act, &old); + if (res) return (__sanitizer_sighandler_ptr)sig_err; + return old.handler; +} + #define TSAN_SYSCALL() \ ThreadState *thr = cur_thread(); \ if (thr->ignore_interceptors) \ @@ -2316,7 +2399,7 @@ struct ScopedSyscall { } }; -#if !SANITIZER_FREEBSD && !SANITIZER_MAC && !SANITIZER_NETBSD +#if !SANITIZER_FREEBSD && !SANITIZER_MAC static void syscall_access_range(uptr pc, uptr p, uptr s, bool write) { TSAN_SYSCALL(); MemoryAccessRange(thr, pc, p, s, write); @@ -2409,6 +2492,7 @@ static void syscall_post_fork(uptr pc, int pid) { syscall_post_fork(GET_CALLER_PC(), res) #include "sanitizer_common/sanitizer_common_syscalls.inc" +#include "sanitizer_common/sanitizer_syscalls_netbsd.inc" #ifdef NEED_TLS_GET_ADDR // Define own interceptor instead of sanitizer_common's for three reasons: @@ -2426,7 +2510,8 @@ TSAN_INTERCEPTOR(void *, __tls_get_addr, void *arg) { ThreadState *thr = cur_thread(); if (!thr) return res; - DTLS::DTV *dtv = DTLS_on_tls_get_addr(arg, res, thr->tls_addr, thr->tls_size); + DTLS::DTV *dtv = DTLS_on_tls_get_addr(arg, res, thr->tls_addr, + thr->tls_addr + thr->tls_size); if (!dtv) return res; // New DTLS block has been allocated. @@ -2435,6 +2520,45 @@ TSAN_INTERCEPTOR(void *, __tls_get_addr, void *arg) { } #endif +#if SANITIZER_NETBSD +TSAN_INTERCEPTOR(void, _lwp_exit) { + SCOPED_TSAN_INTERCEPTOR(_lwp_exit); + DestroyThreadState(); + REAL(_lwp_exit)(); +} +#define TSAN_MAYBE_INTERCEPT__LWP_EXIT TSAN_INTERCEPT(_lwp_exit) +#else +#define TSAN_MAYBE_INTERCEPT__LWP_EXIT +#endif + +#if SANITIZER_FREEBSD +TSAN_INTERCEPTOR(void, thr_exit, tid_t *state) { + SCOPED_TSAN_INTERCEPTOR(thr_exit, state); + DestroyThreadState(); + REAL(thr_exit(state)); +} +#define TSAN_MAYBE_INTERCEPT_THR_EXIT TSAN_INTERCEPT(thr_exit) +#else +#define TSAN_MAYBE_INTERCEPT_THR_EXIT +#endif + +TSAN_INTERCEPTOR_NETBSD_ALIAS(int, cond_init, void *c, void *a) +TSAN_INTERCEPTOR_NETBSD_ALIAS(int, cond_signal, void *c) +TSAN_INTERCEPTOR_NETBSD_ALIAS(int, cond_broadcast, void *c) +TSAN_INTERCEPTOR_NETBSD_ALIAS(int, cond_wait, void *c, void *m) +TSAN_INTERCEPTOR_NETBSD_ALIAS(int, cond_destroy, void *c) +TSAN_INTERCEPTOR_NETBSD_ALIAS(int, mutex_init, void *m, void *a) +TSAN_INTERCEPTOR_NETBSD_ALIAS(int, mutex_destroy, void *m) +TSAN_INTERCEPTOR_NETBSD_ALIAS(int, mutex_trylock, void *m) +TSAN_INTERCEPTOR_NETBSD_ALIAS(int, rwlock_init, void *m, void *a) +TSAN_INTERCEPTOR_NETBSD_ALIAS(int, rwlock_destroy, void *m) +TSAN_INTERCEPTOR_NETBSD_ALIAS(int, rwlock_rdlock, void *m) +TSAN_INTERCEPTOR_NETBSD_ALIAS(int, rwlock_tryrdlock, void *m) +TSAN_INTERCEPTOR_NETBSD_ALIAS(int, rwlock_wrlock, void *m) +TSAN_INTERCEPTOR_NETBSD_ALIAS(int, rwlock_trywrlock, void *m) +TSAN_INTERCEPTOR_NETBSD_ALIAS(int, rwlock_unlock, void *m) +TSAN_INTERCEPTOR_NETBSD_ALIAS_THR(int, once, void *o, void (*f)()) + namespace __tsan { static void finalize(void *arg) { @@ -2466,20 +2590,30 @@ void InitializeInterceptors() { mallopt(-3, 32*1024); // M_MMAP_THRESHOLD #endif + new(interceptor_ctx()) InterceptorContext(); + InitializeCommonInterceptors(); + InitializeSignalInterceptors(); #if !SANITIZER_MAC // We can not use TSAN_INTERCEPT to get setjmp addr, // because it does &setjmp and setjmp is not present in some versions of libc. using __interception::GetRealFunctionAddress; - GetRealFunctionAddress("setjmp", (uptr*)&REAL(setjmp), 0, 0); + GetRealFunctionAddress(TSAN_STRING_SETJMP, + (uptr*)&REAL(setjmp_symname), 0, 0); GetRealFunctionAddress("_setjmp", (uptr*)&REAL(_setjmp), 0, 0); - GetRealFunctionAddress("sigsetjmp", (uptr*)&REAL(sigsetjmp), 0, 0); + GetRealFunctionAddress(TSAN_STRING_SIGSETJMP, + (uptr*)&REAL(sigsetjmp_symname), 0, 0); +#if !SANITIZER_NETBSD GetRealFunctionAddress("__sigsetjmp", (uptr*)&REAL(__sigsetjmp), 0, 0); #endif +#endif - TSAN_INTERCEPT(longjmp); - TSAN_INTERCEPT(siglongjmp); + TSAN_INTERCEPT(longjmp_symname); + TSAN_INTERCEPT(siglongjmp_symname); +#if SANITIZER_NETBSD + TSAN_INTERCEPT(_longjmp); +#endif TSAN_INTERCEPT(malloc); TSAN_INTERCEPT(__libc_memalign); @@ -2487,8 +2621,6 @@ void InitializeInterceptors() { TSAN_INTERCEPT(realloc); TSAN_INTERCEPT(free); TSAN_INTERCEPT(cfree); - TSAN_INTERCEPT(mmap); - TSAN_MAYBE_INTERCEPT_MMAP64; TSAN_INTERCEPT(munmap); TSAN_MAYBE_INTERCEPT_MEMALIGN; TSAN_INTERCEPT(valloc); @@ -2567,15 +2699,10 @@ void InitializeInterceptors() { TSAN_INTERCEPT(unlink); TSAN_INTERCEPT(tmpfile); TSAN_MAYBE_INTERCEPT_TMPFILE64; - TSAN_INTERCEPT(fread); - TSAN_INTERCEPT(fwrite); TSAN_INTERCEPT(abort); - TSAN_INTERCEPT(puts); TSAN_INTERCEPT(rmdir); TSAN_INTERCEPT(closedir); - TSAN_INTERCEPT(sigaction); - TSAN_INTERCEPT(signal); TSAN_INTERCEPT(sigsuspend); TSAN_INTERCEPT(sigblock); TSAN_INTERCEPT(sigsetmask); @@ -2595,7 +2722,7 @@ void InitializeInterceptors() { #if !SANITIZER_ANDROID TSAN_INTERCEPT(dl_iterate_phdr); #endif - TSAN_INTERCEPT(on_exit); + TSAN_MAYBE_INTERCEPT_ON_EXIT; TSAN_INTERCEPT(__cxa_atexit); TSAN_INTERCEPT(_exit); @@ -2603,6 +2730,9 @@ void InitializeInterceptors() { TSAN_INTERCEPT(__tls_get_addr); #endif + TSAN_MAYBE_INTERCEPT__LWP_EXIT; + TSAN_MAYBE_INTERCEPT_THR_EXIT; + #if !SANITIZER_MAC && !SANITIZER_ANDROID // Need to setup it, because interceptors check that the function is resolved. // But atexit is emitted directly into the module, so can't be resolved. @@ -2614,13 +2744,30 @@ void InitializeInterceptors() { Die(); } -#if !SANITIZER_MAC - if (pthread_key_create(&g_thread_finalize_key, &thread_finalize)) { +#if !SANITIZER_MAC && !SANITIZER_NETBSD && !SANITIZER_FREEBSD + if (pthread_key_create(&interceptor_ctx()->finalize_key, &thread_finalize)) { Printf("ThreadSanitizer: failed to create thread key\n"); Die(); } #endif + TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(cond_init); + TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(cond_signal); + TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(cond_broadcast); + TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(cond_wait); + TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(cond_destroy); + TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(mutex_init); + TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(mutex_destroy); + TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(mutex_trylock); + TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(rwlock_init); + TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(rwlock_destroy); + TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(rwlock_rdlock); + TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(rwlock_tryrdlock); + TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(rwlock_wrlock); + TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(rwlock_trywrlock); + TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(rwlock_unlock); + TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS_THR(once); + FdInit(); } diff --git a/libsanitizer/tsan/tsan_interceptors.h b/libsanitizer/tsan/tsan_interceptors.h index de47466..959a394 100644 --- a/libsanitizer/tsan/tsan_interceptors.h +++ b/libsanitizer/tsan/tsan_interceptors.h @@ -49,4 +49,16 @@ LibIgnore *libignore(); #define TSAN_INTERCEPTOR(ret, func, ...) INTERCEPTOR(ret, func, __VA_ARGS__) +#if SANITIZER_NETBSD +# define TSAN_INTERCEPTOR_NETBSD_ALIAS(ret, func, ...) \ + TSAN_INTERCEPTOR(ret, __libc_##func, __VA_ARGS__) \ + ALIAS(WRAPPER_NAME(pthread_##func)); +# define TSAN_INTERCEPTOR_NETBSD_ALIAS_THR(ret, func, ...) \ + TSAN_INTERCEPTOR(ret, __libc_thr_##func, __VA_ARGS__) \ + ALIAS(WRAPPER_NAME(pthread_##func)); +#else +# define TSAN_INTERCEPTOR_NETBSD_ALIAS(ret, func, ...) +# define TSAN_INTERCEPTOR_NETBSD_ALIAS_THR(ret, func, ...) +#endif + #endif // TSAN_INTERCEPTORS_H diff --git a/libsanitizer/tsan/tsan_interceptors_mac.cc b/libsanitizer/tsan/tsan_interceptors_mac.cc index 913e9ed..1df6ac2 100644 --- a/libsanitizer/tsan/tsan_interceptors_mac.cc +++ b/libsanitizer/tsan/tsan_interceptors_mac.cc @@ -98,7 +98,7 @@ OSATOMIC_INTERCEPTORS_BITWISE(OSAtomicXor, fetch_xor, TSAN_INTERCEPTOR(bool, f, t old_value, t new_value, t volatile *ptr) { \ SCOPED_TSAN_INTERCEPTOR(f, old_value, new_value, ptr); \ return tsan_atomic_f##_compare_exchange_strong( \ - (tsan_t *)ptr, (tsan_t *)&old_value, (tsan_t)new_value, \ + (volatile tsan_t *)ptr, (tsan_t *)&old_value, (tsan_t)new_value, \ kMacOrderNonBarrier, kMacOrderNonBarrier); \ } \ \ @@ -106,7 +106,7 @@ OSATOMIC_INTERCEPTORS_BITWISE(OSAtomicXor, fetch_xor, t volatile *ptr) { \ SCOPED_TSAN_INTERCEPTOR(f##Barrier, old_value, new_value, ptr); \ return tsan_atomic_f##_compare_exchange_strong( \ - (tsan_t *)ptr, (tsan_t *)&old_value, (tsan_t)new_value, \ + (volatile tsan_t *)ptr, (tsan_t *)&old_value, (tsan_t)new_value, \ kMacOrderBarrier, kMacOrderNonBarrier); \ } @@ -120,14 +120,14 @@ OSATOMIC_INTERCEPTORS_CAS(OSAtomicCompareAndSwap32, __tsan_atomic32, a32, OSATOMIC_INTERCEPTORS_CAS(OSAtomicCompareAndSwap64, __tsan_atomic64, a64, int64_t) -#define OSATOMIC_INTERCEPTOR_BITOP(f, op, clear, mo) \ - TSAN_INTERCEPTOR(bool, f, uint32_t n, volatile void *ptr) { \ - SCOPED_TSAN_INTERCEPTOR(f, n, ptr); \ - char *byte_ptr = ((char *)ptr) + (n >> 3); \ - char bit = 0x80u >> (n & 7); \ - char mask = clear ? ~bit : bit; \ - char orig_byte = op((a8 *)byte_ptr, mask, mo); \ - return orig_byte & bit; \ +#define OSATOMIC_INTERCEPTOR_BITOP(f, op, clear, mo) \ + TSAN_INTERCEPTOR(bool, f, uint32_t n, volatile void *ptr) { \ + SCOPED_TSAN_INTERCEPTOR(f, n, ptr); \ + volatile char *byte_ptr = ((volatile char *)ptr) + (n >> 3); \ + char bit = 0x80u >> (n & 7); \ + char mask = clear ? ~bit : bit; \ + char orig_byte = op((volatile a8 *)byte_ptr, mask, mo); \ + return orig_byte & bit; \ } #define OSATOMIC_INTERCEPTORS_BITOP(f, op, clear) \ @@ -292,6 +292,43 @@ TSAN_INTERCEPTOR(void, xpc_connection_cancel, xpc_connection_t connection) { #endif // #if defined(__has_include) && __has_include(<xpc/xpc.h>) +// Is the Obj-C object a tagged pointer (i.e. isn't really a valid pointer and +// contains data in the pointers bits instead)? +static bool IsTaggedObjCPointer(void *obj) { + const uptr kPossibleTaggedBits = 0x8000000000000001ull; + return ((uptr)obj & kPossibleTaggedBits) != 0; +} + +// Return an address on which we can synchronize (Acquire and Release) for a +// Obj-C tagged pointer (which is not a valid pointer). Ideally should be a +// derived address from 'obj', but for now just return the same global address. +// TODO(kubamracek): Return different address for different pointers. +static uptr SyncAddressForTaggedPointer(void *obj) { + (void)obj; + static u64 addr; + return (uptr)&addr; +} + +// Address on which we can synchronize for an Objective-C object. Supports +// tagged pointers. +static uptr SyncAddressForObjCObject(void *obj) { + if (IsTaggedObjCPointer(obj)) return SyncAddressForTaggedPointer(obj); + return (uptr)obj; +} + +TSAN_INTERCEPTOR(int, objc_sync_enter, void *obj) { + SCOPED_TSAN_INTERCEPTOR(objc_sync_enter, obj); + int result = REAL(objc_sync_enter)(obj); + if (obj) Acquire(thr, pc, SyncAddressForObjCObject(obj)); + return result; +} + +TSAN_INTERCEPTOR(int, objc_sync_exit, void *obj) { + SCOPED_TSAN_INTERCEPTOR(objc_sync_enter, obj); + if (obj) Release(thr, pc, SyncAddressForObjCObject(obj)); + return REAL(objc_sync_exit)(obj); +} + // On macOS, libc++ is always linked dynamically, so intercepting works the // usual way. #define STDCXX_INTERCEPTOR TSAN_INTERCEPTOR diff --git a/libsanitizer/tsan/tsan_interface.h b/libsanitizer/tsan/tsan_interface.h index 7dc6765..bb097b9 100644 --- a/libsanitizer/tsan/tsan_interface.h +++ b/libsanitizer/tsan/tsan_interface.h @@ -115,6 +115,19 @@ int __tsan_get_report_data(void *report, const char **description, int *count, int *unique_tid_count, void **sleep_trace, uptr trace_size); +/// Retrieves the "tag" from a report (for external-race report types). External +/// races can be associated with a tag which give them more meaning. For example +/// tag value '1' means "Swift access race". Tag value '0' indicated a plain +/// external race. +/// +/// \param report opaque pointer to the current report (obtained as argument in +/// __tsan_on_report, or from __tsan_get_current_report) +/// \param [out] tag points to storage that will be filled with the tag value +/// +/// \returns non-zero value on success, zero on failure +SANITIZER_INTERFACE_ATTRIBUTE +int __tsan_get_report_tag(void *report, uptr *tag); + // Returns information about stack traces included in the report. SANITIZER_INTERFACE_ATTRIBUTE int __tsan_get_report_stack(void *report, uptr idx, void **trace, diff --git a/libsanitizer/tsan/tsan_interface_ann.cc b/libsanitizer/tsan/tsan_interface_ann.cc index 083138f..3e2b7c8 100644 --- a/libsanitizer/tsan/tsan_interface_ann.cc +++ b/libsanitizer/tsan/tsan_interface_ann.cc @@ -12,6 +12,7 @@ #include "sanitizer_common/sanitizer_internal_defs.h" #include "sanitizer_common/sanitizer_placement_new.h" #include "sanitizer_common/sanitizer_stacktrace.h" +#include "sanitizer_common/sanitizer_vector.h" #include "tsan_interface_ann.h" #include "tsan_mutex.h" #include "tsan_report.h" @@ -19,7 +20,6 @@ #include "tsan_mman.h" #include "tsan_flags.h" #include "tsan_platform.h" -#include "tsan_vector.h" #define CALLERPC ((uptr)__builtin_return_address(0)) @@ -183,10 +183,10 @@ void PrintMatchedBenignRaces() { int unique_count = 0; int hit_count = 0; int add_count = 0; - Vector<ExpectRace> hit_matched(MBlockScopedBuf); + Vector<ExpectRace> hit_matched; CollectMatchedBenignRaces(&hit_matched, &unique_count, &hit_count, &ExpectRace::hitcount); - Vector<ExpectRace> add_matched(MBlockScopedBuf); + Vector<ExpectRace> add_matched; CollectMatchedBenignRaces(&add_matched, &unique_count, &add_count, &ExpectRace::addcount); if (hit_matched.Size()) { diff --git a/libsanitizer/tsan/tsan_libdispatch_mac.cc b/libsanitizer/tsan/tsan_libdispatch_mac.cc index 5200a79..f7e08d4 100644 --- a/libsanitizer/tsan/tsan_libdispatch_mac.cc +++ b/libsanitizer/tsan/tsan_libdispatch_mac.cc @@ -23,6 +23,11 @@ #include <dispatch/dispatch.h> #include <pthread.h> +// DISPATCH_NOESCAPE is not defined prior to XCode 8. +#ifndef DISPATCH_NOESCAPE +#define DISPATCH_NOESCAPE +#endif + typedef long long_t; // NOLINT namespace __tsan { @@ -178,11 +183,8 @@ static void invoke_and_release_block(void *param) { TSAN_INTERCEPTOR(void, name, dispatch_queue_t q, \ DISPATCH_NOESCAPE dispatch_block_t block) { \ SCOPED_TSAN_INTERCEPTOR(name, q, block); \ - SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); \ - dispatch_block_t heap_block = Block_copy(block); \ - SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END(); \ tsan_block_context_t new_context = { \ - q, heap_block, &invoke_and_release_block, false, true, barrier, 0}; \ + q, block, &invoke_block, false, true, barrier, 0}; \ Release(thr, pc, (uptr)&new_context); \ SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); \ REAL(name##_f)(q, &new_context, dispatch_callback_wrap); \ @@ -520,9 +522,9 @@ TSAN_INTERCEPTOR(dispatch_data_t, dispatch_data_create, const void *buffer, return REAL(dispatch_data_create)(buffer, size, q, destructor); if (destructor == DISPATCH_DATA_DESTRUCTOR_FREE) - destructor = ^(void) { WRAP(free)((void *)buffer); }; + destructor = ^(void) { WRAP(free)((void *)(uintptr_t)buffer); }; else if (destructor == DISPATCH_DATA_DESTRUCTOR_MUNMAP) - destructor = ^(void) { WRAP(munmap)((void *)buffer, size); }; + destructor = ^(void) { WRAP(munmap)((void *)(uintptr_t)buffer, size); }; SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); dispatch_block_t heap_block = Block_copy(destructor); diff --git a/libsanitizer/tsan/tsan_malloc_mac.cc b/libsanitizer/tsan/tsan_malloc_mac.cc index b418a21..618fa2d 100644 --- a/libsanitizer/tsan/tsan_malloc_mac.cc +++ b/libsanitizer/tsan/tsan_malloc_mac.cc @@ -13,6 +13,7 @@ #include "sanitizer_common/sanitizer_platform.h" #if SANITIZER_MAC +#include "sanitizer_common/sanitizer_errno.h" #include "tsan_interceptors.h" #include "tsan_stack_trace.h" @@ -37,6 +38,15 @@ using namespace __tsan; if (cur_thread()->in_symbolizer) return InternalCalloc(count, size); \ SCOPED_INTERCEPTOR_RAW(calloc, size, count); \ void *p = user_calloc(thr, pc, size, count) +#define COMMON_MALLOC_POSIX_MEMALIGN(memptr, alignment, size) \ + if (cur_thread()->in_symbolizer) { \ + void *p = InternalAlloc(size, nullptr, alignment); \ + if (!p) return errno_ENOMEM; \ + *memptr = p; \ + return 0; \ + } \ + SCOPED_INTERCEPTOR_RAW(posix_memalign, memptr, alignment, size); \ + int res = user_posix_memalign(thr, pc, memptr, alignment, size); #define COMMON_MALLOC_VALLOC(size) \ if (cur_thread()->in_symbolizer) \ return InternalAlloc(size, nullptr, GetPageSizeCached()); \ diff --git a/libsanitizer/tsan/tsan_mman.cc b/libsanitizer/tsan/tsan_mman.cc index 18505ac..76d12a4 100644 --- a/libsanitizer/tsan/tsan_mman.cc +++ b/libsanitizer/tsan/tsan_mman.cc @@ -10,6 +10,7 @@ //===----------------------------------------------------------------------===// #include "sanitizer_common/sanitizer_allocator_checks.h" #include "sanitizer_common/sanitizer_allocator_interface.h" +#include "sanitizer_common/sanitizer_allocator_report.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_errno.h" #include "sanitizer_common/sanitizer_placement_new.h" @@ -148,13 +149,24 @@ static void SignalUnsafeCall(ThreadState *thr, uptr pc) { OutputReport(thr, rep); } +static constexpr uptr kMaxAllowedMallocSize = 1ull << 40; + void *user_alloc_internal(ThreadState *thr, uptr pc, uptr sz, uptr align, bool signal) { - if ((sz >= (1ull << 40)) || (align >= (1ull << 40))) - return Allocator::FailureHandler::OnBadRequest(); + if (sz >= kMaxAllowedMallocSize || align >= kMaxAllowedMallocSize) { + if (AllocatorMayReturnNull()) + return nullptr; + GET_STACK_TRACE_FATAL(thr, pc); + ReportAllocationSizeTooBig(sz, kMaxAllowedMallocSize, &stack); + } void *p = allocator()->Allocate(&thr->proc()->alloc_cache, sz, align); - if (UNLIKELY(p == 0)) - return 0; + if (UNLIKELY(!p)) { + SetAllocatorOutOfMemory(); + if (AllocatorMayReturnNull()) + return nullptr; + GET_STACK_TRACE_FATAL(thr, pc); + ReportOutOfMemory(sz, &stack); + } if (ctx && ctx->initialized) OnUserAlloc(thr, pc, (uptr)p, sz, true); if (signal) @@ -176,8 +188,12 @@ void *user_alloc(ThreadState *thr, uptr pc, uptr sz) { } void *user_calloc(ThreadState *thr, uptr pc, uptr size, uptr n) { - if (UNLIKELY(CheckForCallocOverflow(size, n))) - return SetErrnoOnNull(Allocator::FailureHandler::OnBadRequest()); + if (UNLIKELY(CheckForCallocOverflow(size, n))) { + if (AllocatorMayReturnNull()) + return SetErrnoOnNull(nullptr); + GET_STACK_TRACE_FATAL(thr, pc); + ReportCallocOverflow(n, size, &stack); + } void *p = user_alloc_internal(thr, pc, n * size); if (p) internal_memset(p, 0, n * size); @@ -222,7 +238,10 @@ void *user_realloc(ThreadState *thr, uptr pc, void *p, uptr sz) { void *user_memalign(ThreadState *thr, uptr pc, uptr align, uptr sz) { if (UNLIKELY(!IsPowerOfTwo(align))) { errno = errno_EINVAL; - return Allocator::FailureHandler::OnBadRequest(); + if (AllocatorMayReturnNull()) + return nullptr; + GET_STACK_TRACE_FATAL(thr, pc); + ReportInvalidAllocationAlignment(align, &stack); } return SetErrnoOnNull(user_alloc_internal(thr, pc, sz, align)); } @@ -230,11 +249,14 @@ void *user_memalign(ThreadState *thr, uptr pc, uptr align, uptr sz) { int user_posix_memalign(ThreadState *thr, uptr pc, void **memptr, uptr align, uptr sz) { if (UNLIKELY(!CheckPosixMemalignAlignment(align))) { - Allocator::FailureHandler::OnBadRequest(); - return errno_EINVAL; + if (AllocatorMayReturnNull()) + return errno_EINVAL; + GET_STACK_TRACE_FATAL(thr, pc); + ReportInvalidPosixMemalignAlignment(align, &stack); } void *ptr = user_alloc_internal(thr, pc, sz, align); if (UNLIKELY(!ptr)) + // OOM error is already taken care of by user_alloc_internal. return errno_ENOMEM; CHECK(IsAligned((uptr)ptr, align)); *memptr = ptr; @@ -244,7 +266,10 @@ int user_posix_memalign(ThreadState *thr, uptr pc, void **memptr, uptr align, void *user_aligned_alloc(ThreadState *thr, uptr pc, uptr align, uptr sz) { if (UNLIKELY(!CheckAlignedAllocAlignmentAndSize(align, sz))) { errno = errno_EINVAL; - return Allocator::FailureHandler::OnBadRequest(); + if (AllocatorMayReturnNull()) + return nullptr; + GET_STACK_TRACE_FATAL(thr, pc); + ReportInvalidAlignedAllocAlignment(sz, align, &stack); } return SetErrnoOnNull(user_alloc_internal(thr, pc, sz, align)); } @@ -257,7 +282,10 @@ void *user_pvalloc(ThreadState *thr, uptr pc, uptr sz) { uptr PageSize = GetPageSizeCached(); if (UNLIKELY(CheckForPvallocOverflow(sz, PageSize))) { errno = errno_ENOMEM; - return Allocator::FailureHandler::OnBadRequest(); + if (AllocatorMayReturnNull()) + return nullptr; + GET_STACK_TRACE_FATAL(thr, pc); + ReportPvallocOverflow(sz, &stack); } // pvalloc(0) should allocate one page. sz = sz ? RoundUpTo(sz, PageSize) : PageSize; diff --git a/libsanitizer/tsan/tsan_new_delete.cc b/libsanitizer/tsan/tsan_new_delete.cc index 65ae61b..1346aa7 100644 --- a/libsanitizer/tsan/tsan_new_delete.cc +++ b/libsanitizer/tsan/tsan_new_delete.cc @@ -11,13 +11,16 @@ //===----------------------------------------------------------------------===// #include "interception/interception.h" #include "sanitizer_common/sanitizer_allocator.h" +#include "sanitizer_common/sanitizer_allocator_report.h" #include "sanitizer_common/sanitizer_internal_defs.h" #include "tsan_interceptors.h" +#include "tsan_rtl.h" using namespace __tsan; // NOLINT namespace std { struct nothrow_t {}; +enum class align_val_t: __sanitizer::uptr {}; } // namespace std DECLARE_REAL(void *, malloc, uptr size) @@ -31,7 +34,25 @@ DECLARE_REAL(void, free, void *ptr) { \ SCOPED_INTERCEPTOR_RAW(mangled_name, size); \ p = user_alloc(thr, pc, size); \ - if (!nothrow && UNLIKELY(!p)) DieOnFailure::OnOOM(); \ + if (!nothrow && UNLIKELY(!p)) { \ + GET_STACK_TRACE_FATAL(thr, pc); \ + ReportOutOfMemory(size, &stack); \ + } \ + } \ + invoke_malloc_hook(p, size); \ + return p; + +#define OPERATOR_NEW_BODY_ALIGN(mangled_name, nothrow) \ + if (cur_thread()->in_symbolizer) \ + return InternalAlloc(size, nullptr, (uptr)align); \ + void *p = 0; \ + { \ + SCOPED_INTERCEPTOR_RAW(mangled_name, size); \ + p = user_memalign(thr, pc, (uptr)align, size); \ + if (!nothrow && UNLIKELY(!p)) { \ + GET_STACK_TRACE_FATAL(thr, pc); \ + ReportOutOfMemory(size, &stack); \ + } \ } \ invoke_malloc_hook(p, size); \ return p; @@ -60,6 +81,36 @@ void *operator new[](__sanitizer::uptr size, std::nothrow_t const&) { OPERATOR_NEW_BODY(_ZnamRKSt9nothrow_t, true /*nothrow*/); } +SANITIZER_INTERFACE_ATTRIBUTE +void *operator new(__sanitizer::uptr size, std::align_val_t align); +void *operator new(__sanitizer::uptr size, std::align_val_t align) { + OPERATOR_NEW_BODY_ALIGN(_ZnwmSt11align_val_t, false /*nothrow*/); +} + +SANITIZER_INTERFACE_ATTRIBUTE +void *operator new[](__sanitizer::uptr size, std::align_val_t align); +void *operator new[](__sanitizer::uptr size, std::align_val_t align) { + OPERATOR_NEW_BODY_ALIGN(_ZnamSt11align_val_t, false /*nothrow*/); +} + +SANITIZER_INTERFACE_ATTRIBUTE +void *operator new(__sanitizer::uptr size, std::align_val_t align, + std::nothrow_t const&); +void *operator new(__sanitizer::uptr size, std::align_val_t align, + std::nothrow_t const&) { + OPERATOR_NEW_BODY_ALIGN(_ZnwmSt11align_val_tRKSt9nothrow_t, + true /*nothrow*/); +} + +SANITIZER_INTERFACE_ATTRIBUTE +void *operator new[](__sanitizer::uptr size, std::align_val_t align, + std::nothrow_t const&); +void *operator new[](__sanitizer::uptr size, std::align_val_t align, + std::nothrow_t const&) { + OPERATOR_NEW_BODY_ALIGN(_ZnamSt11align_val_tRKSt9nothrow_t, + true /*nothrow*/); +} + #define OPERATOR_DELETE_BODY(mangled_name) \ if (ptr == 0) return; \ if (cur_thread()->in_symbolizer) \ @@ -91,3 +142,57 @@ void operator delete[](void *ptr, std::nothrow_t const&); void operator delete[](void *ptr, std::nothrow_t const&) { OPERATOR_DELETE_BODY(_ZdaPvRKSt9nothrow_t); } + +SANITIZER_INTERFACE_ATTRIBUTE +void operator delete(void *ptr, __sanitizer::uptr size) NOEXCEPT; +void operator delete(void *ptr, __sanitizer::uptr size) NOEXCEPT { + OPERATOR_DELETE_BODY(_ZdlPvm); +} + +SANITIZER_INTERFACE_ATTRIBUTE +void operator delete[](void *ptr, __sanitizer::uptr size) NOEXCEPT; +void operator delete[](void *ptr, __sanitizer::uptr size) NOEXCEPT { + OPERATOR_DELETE_BODY(_ZdaPvm); +} + +SANITIZER_INTERFACE_ATTRIBUTE +void operator delete(void *ptr, std::align_val_t align) NOEXCEPT; +void operator delete(void *ptr, std::align_val_t align) NOEXCEPT { + OPERATOR_DELETE_BODY(_ZdlPvSt11align_val_t); +} + +SANITIZER_INTERFACE_ATTRIBUTE +void operator delete[](void *ptr, std::align_val_t align) NOEXCEPT; +void operator delete[](void *ptr, std::align_val_t align) NOEXCEPT { + OPERATOR_DELETE_BODY(_ZdaPvSt11align_val_t); +} + +SANITIZER_INTERFACE_ATTRIBUTE +void operator delete(void *ptr, std::align_val_t align, std::nothrow_t const&); +void operator delete(void *ptr, std::align_val_t align, std::nothrow_t const&) { + OPERATOR_DELETE_BODY(_ZdlPvSt11align_val_tRKSt9nothrow_t); +} + +SANITIZER_INTERFACE_ATTRIBUTE +void operator delete[](void *ptr, std::align_val_t align, + std::nothrow_t const&); +void operator delete[](void *ptr, std::align_val_t align, + std::nothrow_t const&) { + OPERATOR_DELETE_BODY(_ZdaPvSt11align_val_tRKSt9nothrow_t); +} + +SANITIZER_INTERFACE_ATTRIBUTE +void operator delete(void *ptr, __sanitizer::uptr size, + std::align_val_t align) NOEXCEPT; +void operator delete(void *ptr, __sanitizer::uptr size, + std::align_val_t align) NOEXCEPT { + OPERATOR_DELETE_BODY(_ZdlPvmSt11align_val_t); +} + +SANITIZER_INTERFACE_ATTRIBUTE +void operator delete[](void *ptr, __sanitizer::uptr size, + std::align_val_t align) NOEXCEPT; +void operator delete[](void *ptr, __sanitizer::uptr size, + std::align_val_t align) NOEXCEPT { + OPERATOR_DELETE_BODY(_ZdaPvmSt11align_val_t); +} diff --git a/libsanitizer/tsan/tsan_platform.h b/libsanitizer/tsan/tsan_platform.h index 44a3ea9..871df46 100644 --- a/libsanitizer/tsan/tsan_platform.h +++ b/libsanitizer/tsan/tsan_platform.h @@ -40,6 +40,19 @@ C/C++ on linux/x86_64 and freebsd/x86_64 7b00 0000 0000 - 7c00 0000 0000: heap 7c00 0000 0000 - 7e80 0000 0000: - 7e80 0000 0000 - 8000 0000 0000: modules and main thread stack + +C/C++ on netbsd/amd64 can reuse the same mapping: + * The address space starts from 0x1000 (option with 0x0) and ends with + 0x7f7ffffff000. + * LoAppMem-kHeapMemEnd can be reused as it is. + * No VDSO support. + * No MidAppMem region. + * No additional HeapMem region. + * HiAppMem contains the stack, loader, shared libraries and heap. + * Stack on NetBSD/amd64 has prereserved 128MB. + * Heap grows downwards (top-down). + * ASLR must be disabled per-process or globally. + */ struct Mapping { static const uptr kMetaShadowBeg = 0x300000000000ull; @@ -64,25 +77,27 @@ struct Mapping { #define TSAN_MID_APP_RANGE 1 #elif defined(__mips64) /* -C/C++ on linux/mips64 -0100 0000 00 - 0200 0000 00: main binary -0200 0000 00 - 1400 0000 00: - -1400 0000 00 - 2400 0000 00: shadow -2400 0000 00 - 3000 0000 00: - -3000 0000 00 - 4000 0000 00: metainfo (memory blocks and sync objects) -4000 0000 00 - 6000 0000 00: - -6000 0000 00 - 6200 0000 00: traces -6200 0000 00 - fe00 0000 00: - -fe00 0000 00 - ff00 0000 00: heap -ff00 0000 00 - ff80 0000 00: - -ff80 0000 00 - ffff ffff ff: modules and main thread stack +C/C++ on linux/mips64 (40-bit VMA) +0000 0000 00 - 0100 0000 00: - (4 GB) +0100 0000 00 - 0200 0000 00: main binary (4 GB) +0200 0000 00 - 2000 0000 00: - (120 GB) +2000 0000 00 - 4000 0000 00: shadow (128 GB) +4000 0000 00 - 5000 0000 00: metainfo (memory blocks and sync objects) (64 GB) +5000 0000 00 - aa00 0000 00: - (360 GB) +aa00 0000 00 - ab00 0000 00: main binary (PIE) (4 GB) +ab00 0000 00 - b000 0000 00: - (20 GB) +b000 0000 00 - b200 0000 00: traces (8 GB) +b200 0000 00 - fe00 0000 00: - (304 GB) +fe00 0000 00 - ff00 0000 00: heap (4 GB) +ff00 0000 00 - ff80 0000 00: - (2 GB) +ff80 0000 00 - ffff ffff ff: modules and main thread stack (<2 GB) */ struct Mapping { static const uptr kMetaShadowBeg = 0x4000000000ull; static const uptr kMetaShadowEnd = 0x5000000000ull; static const uptr kTraceMemBeg = 0xb000000000ull; static const uptr kTraceMemEnd = 0xb200000000ull; - static const uptr kShadowBeg = 0x2400000000ull; + static const uptr kShadowBeg = 0x2000000000ull; static const uptr kShadowEnd = 0x4000000000ull; static const uptr kHeapMemBeg = 0xfe00000000ull; static const uptr kHeapMemEnd = 0xff00000000ull; @@ -109,7 +124,8 @@ C/C++ on Darwin/iOS/ARM64 (36-bit VMA, 64 GB VM) 0c00 0000 00 - 0d00 0000 00: - (4 GB) 0d00 0000 00 - 0e00 0000 00: metainfo (4 GB) 0e00 0000 00 - 0f00 0000 00: - (4 GB) -0f00 0000 00 - 1000 0000 00: traces (4 GB) +0f00 0000 00 - 0fc0 0000 00: traces (3 GB) +0fc0 0000 00 - 1000 0000 00: - */ struct Mapping { static const uptr kLoAppMemBeg = 0x0100000000ull; @@ -121,9 +137,9 @@ struct Mapping { static const uptr kMetaShadowBeg = 0x0d00000000ull; static const uptr kMetaShadowEnd = 0x0e00000000ull; static const uptr kTraceMemBeg = 0x0f00000000ull; - static const uptr kTraceMemEnd = 0x1000000000ull; - static const uptr kHiAppMemBeg = 0x1000000000ull; - static const uptr kHiAppMemEnd = 0x1000000000ull; + static const uptr kTraceMemEnd = 0x0fc0000000ull; + static const uptr kHiAppMemBeg = 0x0fc0000000ull; + static const uptr kHiAppMemEnd = 0x0fc0000000ull; static const uptr kAppMemMsk = 0x0ull; static const uptr kAppMemXor = 0x0ull; static const uptr kVdsoBeg = 0x7000000000000000ull; @@ -337,9 +353,9 @@ struct Mapping47 { #define TSAN_RUNTIME_VMA 1 #endif -#elif SANITIZER_GO && !SANITIZER_WINDOWS +#elif SANITIZER_GO && !SANITIZER_WINDOWS && defined(__x86_64__) -/* Go on linux, darwin and freebsd +/* Go on linux, darwin and freebsd on x86_64 0000 0000 1000 - 0000 1000 0000: executable 0000 1000 0000 - 00c0 0000 0000: - 00c0 0000 0000 - 00e0 0000 0000: heap @@ -388,6 +404,87 @@ struct Mapping { static const uptr kAppMemEnd = 0x00e000000000ull; }; +#elif SANITIZER_GO && defined(__powerpc64__) + +/* Only Mapping46 and Mapping47 are currently supported for powercp64 on Go. */ + +/* Go on linux/powerpc64 (46-bit VMA) +0000 0000 1000 - 0000 1000 0000: executable +0000 1000 0000 - 00c0 0000 0000: - +00c0 0000 0000 - 00e0 0000 0000: heap +00e0 0000 0000 - 2000 0000 0000: - +2000 0000 0000 - 2380 0000 0000: shadow +2380 0000 0000 - 2400 0000 0000: - +2400 0000 0000 - 3400 0000 0000: metainfo (memory blocks and sync objects) +3400 0000 0000 - 3600 0000 0000: - +3600 0000 0000 - 3800 0000 0000: traces +3800 0000 0000 - 4000 0000 0000: - +*/ + +struct Mapping46 { + static const uptr kMetaShadowBeg = 0x240000000000ull; + static const uptr kMetaShadowEnd = 0x340000000000ull; + static const uptr kTraceMemBeg = 0x360000000000ull; + static const uptr kTraceMemEnd = 0x380000000000ull; + static const uptr kShadowBeg = 0x200000000000ull; + static const uptr kShadowEnd = 0x238000000000ull; + static const uptr kAppMemBeg = 0x000000001000ull; + static const uptr kAppMemEnd = 0x00e000000000ull; +}; + +/* Go on linux/powerpc64 (47-bit VMA) +0000 0000 1000 - 0000 1000 0000: executable +0000 1000 0000 - 00c0 0000 0000: - +00c0 0000 0000 - 00e0 0000 0000: heap +00e0 0000 0000 - 2000 0000 0000: - +2000 0000 0000 - 3000 0000 0000: shadow +3000 0000 0000 - 3000 0000 0000: - +3000 0000 0000 - 4000 0000 0000: metainfo (memory blocks and sync objects) +4000 0000 0000 - 6000 0000 0000: - +6000 0000 0000 - 6200 0000 0000: traces +6200 0000 0000 - 8000 0000 0000: - +*/ + +struct Mapping47 { + static const uptr kMetaShadowBeg = 0x300000000000ull; + static const uptr kMetaShadowEnd = 0x400000000000ull; + static const uptr kTraceMemBeg = 0x600000000000ull; + static const uptr kTraceMemEnd = 0x620000000000ull; + static const uptr kShadowBeg = 0x200000000000ull; + static const uptr kShadowEnd = 0x300000000000ull; + static const uptr kAppMemBeg = 0x000000001000ull; + static const uptr kAppMemEnd = 0x00e000000000ull; +}; + +#elif SANITIZER_GO && defined(__aarch64__) + +/* Go on linux/aarch64 (48-bit VMA) +0000 0000 1000 - 0000 1000 0000: executable +0000 1000 0000 - 00c0 0000 0000: - +00c0 0000 0000 - 00e0 0000 0000: heap +00e0 0000 0000 - 2000 0000 0000: - +2000 0000 0000 - 3000 0000 0000: shadow +3000 0000 0000 - 3000 0000 0000: - +3000 0000 0000 - 4000 0000 0000: metainfo (memory blocks and sync objects) +4000 0000 0000 - 6000 0000 0000: - +6000 0000 0000 - 6200 0000 0000: traces +6200 0000 0000 - 8000 0000 0000: - +*/ + +struct Mapping { + static const uptr kMetaShadowBeg = 0x300000000000ull; + static const uptr kMetaShadowEnd = 0x400000000000ull; + static const uptr kTraceMemBeg = 0x600000000000ull; + static const uptr kTraceMemEnd = 0x620000000000ull; + static const uptr kShadowBeg = 0x200000000000ull; + static const uptr kShadowEnd = 0x300000000000ull; + static const uptr kAppMemBeg = 0x000000001000ull; + static const uptr kAppMemEnd = 0x00e000000000ull; +}; + +// Indicates the runtime will define the memory regions at runtime. +#define TSAN_RUNTIME_VMA 1 + #else # error "Unknown platform" #endif @@ -450,7 +547,7 @@ uptr MappingImpl(void) { template<int Type> uptr MappingArchImpl(void) { -#if defined(__aarch64__) && !defined(__APPLE__) +#if defined(__aarch64__) && !defined(__APPLE__) && !SANITIZER_GO switch (vmaSize) { case 39: return MappingImpl<Mapping39, Type>(); case 42: return MappingImpl<Mapping42, Type>(); @@ -460,7 +557,9 @@ uptr MappingArchImpl(void) { return 0; #elif defined(__powerpc64__) switch (vmaSize) { +#if !SANITIZER_GO case 44: return MappingImpl<Mapping44, Type>(); +#endif case 46: return MappingImpl<Mapping46, Type>(); case 47: return MappingImpl<Mapping47, Type>(); } @@ -605,7 +704,7 @@ bool IsAppMemImpl(uptr mem) { ALWAYS_INLINE bool IsAppMem(uptr mem) { -#if defined(__aarch64__) && !defined(__APPLE__) +#if defined(__aarch64__) && !defined(__APPLE__) && !SANITIZER_GO switch (vmaSize) { case 39: return IsAppMemImpl<Mapping39>(mem); case 42: return IsAppMemImpl<Mapping42>(mem); @@ -615,7 +714,9 @@ bool IsAppMem(uptr mem) { return false; #elif defined(__powerpc64__) switch (vmaSize) { +#if !SANITIZER_GO case 44: return IsAppMemImpl<Mapping44>(mem); +#endif case 46: return IsAppMemImpl<Mapping46>(mem); case 47: return IsAppMemImpl<Mapping47>(mem); } @@ -634,7 +735,7 @@ bool IsShadowMemImpl(uptr mem) { ALWAYS_INLINE bool IsShadowMem(uptr mem) { -#if defined(__aarch64__) && !defined(__APPLE__) +#if defined(__aarch64__) && !defined(__APPLE__) && !SANITIZER_GO switch (vmaSize) { case 39: return IsShadowMemImpl<Mapping39>(mem); case 42: return IsShadowMemImpl<Mapping42>(mem); @@ -644,7 +745,9 @@ bool IsShadowMem(uptr mem) { return false; #elif defined(__powerpc64__) switch (vmaSize) { +#if !SANITIZER_GO case 44: return IsShadowMemImpl<Mapping44>(mem); +#endif case 46: return IsShadowMemImpl<Mapping46>(mem); case 47: return IsShadowMemImpl<Mapping47>(mem); } @@ -663,7 +766,7 @@ bool IsMetaMemImpl(uptr mem) { ALWAYS_INLINE bool IsMetaMem(uptr mem) { -#if defined(__aarch64__) && !defined(__APPLE__) +#if defined(__aarch64__) && !defined(__APPLE__) && !SANITIZER_GO switch (vmaSize) { case 39: return IsMetaMemImpl<Mapping39>(mem); case 42: return IsMetaMemImpl<Mapping42>(mem); @@ -673,7 +776,9 @@ bool IsMetaMem(uptr mem) { return false; #elif defined(__powerpc64__) switch (vmaSize) { +#if !SANITIZER_GO case 44: return IsMetaMemImpl<Mapping44>(mem); +#endif case 46: return IsMetaMemImpl<Mapping46>(mem); case 47: return IsMetaMemImpl<Mapping47>(mem); } @@ -702,7 +807,7 @@ uptr MemToShadowImpl(uptr x) { ALWAYS_INLINE uptr MemToShadow(uptr x) { -#if defined(__aarch64__) && !defined(__APPLE__) +#if defined(__aarch64__) && !defined(__APPLE__) && !SANITIZER_GO switch (vmaSize) { case 39: return MemToShadowImpl<Mapping39>(x); case 42: return MemToShadowImpl<Mapping42>(x); @@ -712,7 +817,9 @@ uptr MemToShadow(uptr x) { return 0; #elif defined(__powerpc64__) switch (vmaSize) { +#if !SANITIZER_GO case 44: return MemToShadowImpl<Mapping44>(x); +#endif case 46: return MemToShadowImpl<Mapping46>(x); case 47: return MemToShadowImpl<Mapping47>(x); } @@ -743,7 +850,7 @@ u32 *MemToMetaImpl(uptr x) { ALWAYS_INLINE u32 *MemToMeta(uptr x) { -#if defined(__aarch64__) && !defined(__APPLE__) +#if defined(__aarch64__) && !defined(__APPLE__) && !SANITIZER_GO switch (vmaSize) { case 39: return MemToMetaImpl<Mapping39>(x); case 42: return MemToMetaImpl<Mapping42>(x); @@ -753,7 +860,9 @@ u32 *MemToMeta(uptr x) { return 0; #elif defined(__powerpc64__) switch (vmaSize) { +#if !SANITIZER_GO case 44: return MemToMetaImpl<Mapping44>(x); +#endif case 46: return MemToMetaImpl<Mapping46>(x); case 47: return MemToMetaImpl<Mapping47>(x); } @@ -797,7 +906,7 @@ uptr ShadowToMemImpl(uptr s) { ALWAYS_INLINE uptr ShadowToMem(uptr s) { -#if defined(__aarch64__) && !defined(__APPLE__) +#if defined(__aarch64__) && !defined(__APPLE__) && !SANITIZER_GO switch (vmaSize) { case 39: return ShadowToMemImpl<Mapping39>(s); case 42: return ShadowToMemImpl<Mapping42>(s); @@ -807,7 +916,9 @@ uptr ShadowToMem(uptr s) { return 0; #elif defined(__powerpc64__) switch (vmaSize) { +#if !SANITIZER_GO case 44: return ShadowToMemImpl<Mapping44>(s); +#endif case 46: return ShadowToMemImpl<Mapping46>(s); case 47: return ShadowToMemImpl<Mapping47>(s); } @@ -834,7 +945,7 @@ uptr GetThreadTraceImpl(int tid) { ALWAYS_INLINE uptr GetThreadTrace(int tid) { -#if defined(__aarch64__) && !defined(__APPLE__) +#if defined(__aarch64__) && !defined(__APPLE__) && !SANITIZER_GO switch (vmaSize) { case 39: return GetThreadTraceImpl<Mapping39>(tid); case 42: return GetThreadTraceImpl<Mapping42>(tid); @@ -844,7 +955,9 @@ uptr GetThreadTrace(int tid) { return 0; #elif defined(__powerpc64__) switch (vmaSize) { +#if !SANITIZER_GO case 44: return GetThreadTraceImpl<Mapping44>(tid); +#endif case 46: return GetThreadTraceImpl<Mapping46>(tid); case 47: return GetThreadTraceImpl<Mapping47>(tid); } @@ -866,7 +979,7 @@ uptr GetThreadTraceHeaderImpl(int tid) { ALWAYS_INLINE uptr GetThreadTraceHeader(int tid) { -#if defined(__aarch64__) && !defined(__APPLE__) +#if defined(__aarch64__) && !defined(__APPLE__) && !SANITIZER_GO switch (vmaSize) { case 39: return GetThreadTraceHeaderImpl<Mapping39>(tid); case 42: return GetThreadTraceHeaderImpl<Mapping42>(tid); @@ -876,7 +989,9 @@ uptr GetThreadTraceHeader(int tid) { return 0; #elif defined(__powerpc64__) switch (vmaSize) { +#if !SANITIZER_GO case 44: return GetThreadTraceHeaderImpl<Mapping44>(tid); +#endif case 46: return GetThreadTraceHeaderImpl<Mapping46>(tid); case 47: return GetThreadTraceHeaderImpl<Mapping47>(tid); } diff --git a/libsanitizer/tsan/tsan_platform_linux.cc b/libsanitizer/tsan/tsan_platform_linux.cc index d46dff4..9b4dea2 100644 --- a/libsanitizer/tsan/tsan_platform_linux.cc +++ b/libsanitizer/tsan/tsan_platform_linux.cc @@ -12,11 +12,12 @@ #include "sanitizer_common/sanitizer_platform.h" -#if SANITIZER_LINUX || SANITIZER_FREEBSD +#if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_linux.h" +#include "sanitizer_common/sanitizer_platform_limits_netbsd.h" #include "sanitizer_common/sanitizer_platform_limits_posix.h" #include "sanitizer_common/sanitizer_posix.h" #include "sanitizer_common/sanitizer_procmaps.h" @@ -165,11 +166,11 @@ static void MapRodata() { fd_t fd = openrv; // Fill the file with kShadowRodata. const uptr kMarkerSize = 512 * 1024 / sizeof(u64); - InternalScopedBuffer<u64> marker(kMarkerSize); + InternalMmapVector<u64> marker(kMarkerSize); // volatile to prevent insertion of memset for (volatile u64 *p = marker.data(); p < marker.data() + kMarkerSize; p++) *p = kShadowRodata; - internal_write(fd, marker.data(), marker.size()); + internal_write(fd, marker.data(), marker.size() * sizeof(u64)); // Map the file into memory. uptr page = internal_mmap(0, GetPageSizeCached(), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, fd, 0); @@ -188,8 +189,9 @@ static void MapRodata() { // Assume it's .rodata char *shadow_start = (char *)MemToShadow(segment.start); char *shadow_end = (char *)MemToShadow(segment.end); - for (char *p = shadow_start; p < shadow_end; p += marker.size()) { - internal_mmap(p, Min<uptr>(marker.size(), shadow_end - p), + for (char *p = shadow_start; p < shadow_end; + p += marker.size() * sizeof(u64)) { + internal_mmap(p, Min<uptr>(marker.size() * sizeof(u64), shadow_end - p), PROT_READ, MAP_PRIVATE | MAP_FIXED, fd, 0); } } @@ -208,17 +210,33 @@ void InitializePlatformEarly() { vmaSize = (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1); #if defined(__aarch64__) +# if !SANITIZER_GO if (vmaSize != 39 && vmaSize != 42 && vmaSize != 48) { Printf("FATAL: ThreadSanitizer: unsupported VMA range\n"); - Printf("FATAL: Found %d - Supported 39, 42 and 48\n", vmaSize); + Printf("FATAL: Found %zd - Supported 39, 42 and 48\n", vmaSize); Die(); } +#else + if (vmaSize != 48) { + Printf("FATAL: ThreadSanitizer: unsupported VMA range\n"); + Printf("FATAL: Found %zd - Supported 48\n", vmaSize); + Die(); + } +#endif #elif defined(__powerpc64__) +# if !SANITIZER_GO if (vmaSize != 44 && vmaSize != 46 && vmaSize != 47) { Printf("FATAL: ThreadSanitizer: unsupported VMA range\n"); - Printf("FATAL: Found %d - Supported 44, 46, and 47\n", vmaSize); + Printf("FATAL: Found %zd - Supported 44, 46, and 47\n", vmaSize); + Die(); + } +# else + if (vmaSize != 46 && vmaSize != 47) { + Printf("FATAL: ThreadSanitizer: unsupported VMA range\n"); + Printf("FATAL: Found %zd - Supported 46, and 47\n", vmaSize); Die(); } +# endif #endif #endif } @@ -399,4 +417,4 @@ void cur_thread_finalize() { } // namespace __tsan -#endif // SANITIZER_LINUX || SANITIZER_FREEBSD +#endif // SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD diff --git a/libsanitizer/tsan/tsan_platform_mac.cc b/libsanitizer/tsan/tsan_platform_mac.cc index 8eb22fa..14395ba 100644 --- a/libsanitizer/tsan/tsan_platform_mac.cc +++ b/libsanitizer/tsan/tsan_platform_mac.cc @@ -229,7 +229,7 @@ static void my_pthread_introspection_hook(unsigned int event, pthread_t thread, void InitializePlatformEarly() { #if defined(__aarch64__) - uptr max_vm = GetMaxVirtualAddress() + 1; + uptr max_vm = GetMaxUserVirtualAddress() + 1; if (max_vm != Mapping::kHiAppMemEnd) { Printf("ThreadSanitizer: unsupported vm address limit %p, expected %p.\n", max_vm, Mapping::kHiAppMemEnd); @@ -238,6 +238,9 @@ void InitializePlatformEarly() { #endif } +static const uptr kPthreadSetjmpXorKeySlot = 0x7; +extern "C" uptr __tsan_darwin_setjmp_xor_key = 0; + void InitializePlatform() { DisableCoreDumperIfNecessary(); #if !SANITIZER_GO @@ -249,6 +252,11 @@ void InitializePlatform() { prev_pthread_introspection_hook = pthread_introspection_hook_install(&my_pthread_introspection_hook); #endif + + if (GetMacosVersion() >= MACOS_VERSION_MOJAVE) { + __tsan_darwin_setjmp_xor_key = + (uptr)pthread_getspecific(kPthreadSetjmpXorKeySlot); + } } #if !SANITIZER_GO diff --git a/libsanitizer/tsan/tsan_platform_posix.cc b/libsanitizer/tsan/tsan_platform_posix.cc index 6e62575..df9b6d4 100644 --- a/libsanitizer/tsan/tsan_platform_posix.cc +++ b/libsanitizer/tsan/tsan_platform_posix.cc @@ -14,6 +14,7 @@ #if SANITIZER_POSIX #include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_errno.h" #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_procmaps.h" #include "tsan_platform.h" @@ -21,16 +22,39 @@ namespace __tsan { +static const char kShadowMemoryMappingWarning[] = + "FATAL: %s can not madvise shadow region [%zx, %zx] with %s (errno: %d)\n"; +static const char kShadowMemoryMappingHint[] = + "HINT: if %s is not supported in your environment, you may set " + "TSAN_OPTIONS=%s=0\n"; + +static void NoHugePagesInShadow(uptr addr, uptr size) { + if (common_flags()->no_huge_pages_for_shadow) + if (!NoHugePagesInRegion(addr, size)) { + Printf(kShadowMemoryMappingWarning, SanitizerToolName, addr, addr + size, + "MADV_NOHUGEPAGE", errno); + Printf(kShadowMemoryMappingHint, "MADV_NOHUGEPAGE", + "no_huge_pages_for_shadow"); + Die(); + } +} + +static void DontDumpShadow(uptr addr, uptr size) { + if (common_flags()->use_madv_dontdump) + if (!DontDumpShadowMemory(addr, size)) { + Printf(kShadowMemoryMappingWarning, SanitizerToolName, addr, addr + size, + "MADV_DONTDUMP", errno); + Printf(kShadowMemoryMappingHint, "MADV_DONTDUMP", "use_madv_dontdump"); + Die(); + } +} + #if !SANITIZER_GO void InitializeShadowMemory() { // Map memory shadow. - uptr shadow = - (uptr)MmapFixedNoReserve(ShadowBeg(), ShadowEnd() - ShadowBeg(), - "shadow"); - if (shadow != ShadowBeg()) { + if (!MmapFixedNoReserve(ShadowBeg(), ShadowEnd() - ShadowBeg(), "shadow")) { Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n"); - Printf("FATAL: Make sure to compile with -fPIE and " - "to link with -pie (%p, %p).\n", shadow, ShadowBeg()); + Printf("FATAL: Make sure to compile with -fPIE and to link with -pie.\n"); Die(); } // This memory range is used for thread stacks and large user mmaps. @@ -72,30 +96,23 @@ void InitializeShadowMemory() { DCHECK(0); } #endif - NoHugePagesInRegion(MemToShadow(kMadviseRangeBeg), + NoHugePagesInShadow(MemToShadow(kMadviseRangeBeg), kMadviseRangeSize * kShadowMultiplier); - // Meta shadow is compressing and we don't flush it, - // so it makes sense to mark it as NOHUGEPAGE to not over-allocate memory. - // On one program it reduces memory consumption from 5GB to 2.5GB. - NoHugePagesInRegion(MetaShadowBeg(), MetaShadowEnd() - MetaShadowBeg()); - if (common_flags()->use_madv_dontdump) - DontDumpShadowMemory(ShadowBeg(), ShadowEnd() - ShadowBeg()); + DontDumpShadow(ShadowBeg(), ShadowEnd() - ShadowBeg()); DPrintf("memory shadow: %zx-%zx (%zuGB)\n", ShadowBeg(), ShadowEnd(), (ShadowEnd() - ShadowBeg()) >> 30); // Map meta shadow. - uptr meta_size = MetaShadowEnd() - MetaShadowBeg(); - uptr meta = - (uptr)MmapFixedNoReserve(MetaShadowBeg(), meta_size, "meta shadow"); - if (meta != MetaShadowBeg()) { + const uptr meta = MetaShadowBeg(); + const uptr meta_size = MetaShadowEnd() - meta; + if (!MmapFixedNoReserve(meta, meta_size, "meta shadow")) { Printf("FATAL: ThreadSanitizer can not mmap the shadow memory\n"); - Printf("FATAL: Make sure to compile with -fPIE and " - "to link with -pie (%p, %p).\n", meta, MetaShadowBeg()); + Printf("FATAL: Make sure to compile with -fPIE and to link with -pie.\n"); Die(); } - if (common_flags()->use_madv_dontdump) - DontDumpShadowMemory(meta, meta_size); + NoHugePagesInShadow(meta, meta_size); + DontDumpShadow(meta, meta_size); DPrintf("meta shadow: %zx-%zx (%zuGB)\n", meta, meta + meta_size, meta_size >> 30); diff --git a/libsanitizer/tsan/tsan_report.cc b/libsanitizer/tsan/tsan_report.cc index f8cb3e7..4dffc34 100644 --- a/libsanitizer/tsan/tsan_report.cc +++ b/libsanitizer/tsan/tsan_report.cc @@ -46,18 +46,18 @@ class Decorator: public __sanitizer::SanitizerCommonDecorator { ReportDesc::ReportDesc() : tag(kExternalTagNone) - , stacks(MBlockReportStack) - , mops(MBlockReportMop) - , locs(MBlockReportLoc) - , mutexes(MBlockReportMutex) - , threads(MBlockReportThread) - , unique_tids(MBlockReportThread) + , stacks() + , mops() + , locs() + , mutexes() + , threads() + , unique_tids() , sleep() , count() { } ReportMop::ReportMop() - : mset(MBlockReportMutex) { + : mset() { } ReportDesc::~ReportDesc() { diff --git a/libsanitizer/tsan/tsan_report.h b/libsanitizer/tsan/tsan_report.h index 6eb043f..8e96e97 100644 --- a/libsanitizer/tsan/tsan_report.h +++ b/libsanitizer/tsan/tsan_report.h @@ -12,8 +12,8 @@ #define TSAN_REPORT_H #include "sanitizer_common/sanitizer_symbolizer.h" +#include "sanitizer_common/sanitizer_vector.h" #include "tsan_defs.h" -#include "tsan_vector.h" namespace __tsan { diff --git a/libsanitizer/tsan/tsan_rtl.cc b/libsanitizer/tsan/tsan_rtl.cc index 4a1f500..bd0892d 100644 --- a/libsanitizer/tsan/tsan_rtl.cc +++ b/libsanitizer/tsan/tsan_rtl.cc @@ -100,11 +100,11 @@ Context::Context() , thread_registry(new(thread_registry_placeholder) ThreadRegistry( CreateThreadContext, kMaxTid, kThreadQuarantineSize, kMaxTidReuse)) , racy_mtx(MutexTypeRacy, StatMtxRacy) - , racy_stacks(MBlockRacyStacks) - , racy_addresses(MBlockRacyAddresses) + , racy_stacks() + , racy_addresses() , fired_suppressions_mtx(MutexTypeFired, StatMtxFired) - , fired_suppressions(8) , clock_alloc("clock allocator") { + fired_suppressions.reserve(8); } // The objects are allocated in TLS, so one may rely on zero-initialization. @@ -119,7 +119,7 @@ ThreadState::ThreadState(Context *ctx, int tid, int unique_id, u64 epoch, // , ignore_interceptors() , clock(tid, reuse_count) #if !SANITIZER_GO - , jmp_bufs(MBlockJmpBuf) + , jmp_bufs() #endif , tid(tid) , unique_id(unique_id) @@ -138,7 +138,7 @@ static void MemoryProfiler(Context *ctx, fd_t fd, int i) { uptr n_threads; uptr n_running_threads; ctx->thread_registry->GetNumberOfThreads(&n_threads, &n_running_threads); - InternalScopedBuffer<char> buf(4096); + InternalMmapVector<char> buf(4096); WriteMemoryProfile(buf.data(), buf.size(), n_threads, n_running_threads); WriteToFile(fd, buf.data(), internal_strlen(buf.data())); } @@ -212,7 +212,7 @@ static void BackgroundThread(void *arg) { memory_order_relaxed); if (last != 0 && last + flags()->flush_symbolizer_ms * kMs2Ns < now) { Lock l(&ctx->report_mtx); - SpinMutexLock l2(&CommonSanitizerReportMutex); + ScopedErrorReportLock l2; SymbolizeFlush(); atomic_store(&ctx->last_symbolize_time_ns, 0, memory_order_relaxed); } @@ -244,7 +244,8 @@ void MapShadow(uptr addr, uptr size) { const uptr kPageSize = GetPageSizeCached(); uptr shadow_begin = RoundDownTo((uptr)MemToShadow(addr), kPageSize); uptr shadow_end = RoundUpTo((uptr)MemToShadow(addr + size), kPageSize); - MmapFixedNoReserve(shadow_begin, shadow_end - shadow_begin, "shadow"); + if (!MmapFixedNoReserve(shadow_begin, shadow_end - shadow_begin, "shadow")) + Die(); // Meta shadow is 2:1, so tread carefully. static bool data_mapped = false; @@ -256,7 +257,8 @@ void MapShadow(uptr addr, uptr size) { if (!data_mapped) { // First call maps data+bss. data_mapped = true; - MmapFixedNoReserve(meta_begin, meta_end - meta_begin, "meta shadow"); + if (!MmapFixedNoReserve(meta_begin, meta_end - meta_begin, "meta shadow")) + Die(); } else { // Mapping continous heap. // Windows wants 64K alignment. @@ -266,7 +268,8 @@ void MapShadow(uptr addr, uptr size) { return; if (meta_begin < mapped_meta_end) meta_begin = mapped_meta_end; - MmapFixedNoReserve(meta_begin, meta_end - meta_begin, "meta shadow"); + if (!MmapFixedNoReserve(meta_begin, meta_end - meta_begin, "meta shadow")) + Die(); mapped_meta_end = meta_end; } VPrintf(2, "mapped meta shadow for (%p-%p) at (%p-%p)\n", @@ -278,10 +281,9 @@ void MapThreadTrace(uptr addr, uptr size, const char *name) { CHECK_GE(addr, TraceMemBeg()); CHECK_LE(addr + size, TraceMemEnd()); CHECK_EQ(addr, addr & ~((64 << 10) - 1)); // windows wants 64K alignment - uptr addr1 = (uptr)MmapFixedNoReserve(addr, size, name); - if (addr1 != addr) { - Printf("FATAL: ThreadSanitizer can not mmap thread trace (%p/%p->%p)\n", - addr, size, addr1); + if (!MmapFixedNoReserve(addr, size, name)) { + Printf("FATAL: ThreadSanitizer can not mmap thread trace (%p/%p)\n", + addr, size); Die(); } } @@ -322,6 +324,21 @@ static void CheckShadowMapping() { } } +#if !SANITIZER_GO +static void OnStackUnwind(const SignalContext &sig, const void *, + BufferedStackTrace *stack) { + uptr top = 0; + uptr bottom = 0; + bool fast = common_flags()->fast_unwind_on_fatal; + if (fast) GetThreadStackTopAndBottom(false, &top, &bottom); + stack->Unwind(kStackTraceMax, sig.pc, sig.bp, sig.context, top, bottom, fast); +} + +static void TsanOnDeadlySignal(int signo, void *siginfo, void *context) { + HandleDeadlySignal(siginfo, context, GetTid(), &OnStackUnwind, nullptr); +} +#endif + void Initialize(ThreadState *thr) { // Thread safe because done before all threads exist. static bool is_initialized = false; @@ -337,6 +354,7 @@ void Initialize(ThreadState *thr) { ctx = new(ctx_placeholder) Context; const char *options = GetEnv(SANITIZER_GO ? "GORACE" : "TSAN_OPTIONS"); CacheBinaryName(); + CheckASLR(); InitializeFlags(&ctx->flags, options); AvoidCVE_2016_2143(); InitializePlatformEarly(); @@ -359,6 +377,7 @@ void Initialize(ThreadState *thr) { #if !SANITIZER_GO InitializeShadowMemory(); InitializeAllocatorLate(); + InstallDeadlySignalHandlers(TsanOnDeadlySignal); #endif // Setup correct file descriptor for error reports. __sanitizer_set_report_path(common_flags()->log_path); @@ -366,13 +385,6 @@ void Initialize(ThreadState *thr) { #if !SANITIZER_GO InitializeLibIgnore(); Symbolizer::GetOrInit()->AddHooks(EnterSymbolizer, ExitSymbolizer); - // On MIPS, TSan initialization is run before - // __pthread_initialize_minimal_internal() is finished, so we can not spawn - // new threads. -#ifndef __mips__ - StartBackgroundThread(); - SetSandboxingCallback(StopBackgroundThread); -#endif #endif VPrintf(1, "***** Running under ThreadSanitizer v2 (pid %d) *****\n", @@ -401,6 +413,21 @@ void Initialize(ThreadState *thr) { OnInitialize(); } +void MaybeSpawnBackgroundThread() { + // On MIPS, TSan initialization is run before + // __pthread_initialize_minimal_internal() is finished, so we can not spawn + // new threads. +#if !SANITIZER_GO && !defined(__mips__) + static atomic_uint32_t bg_thread = {}; + if (atomic_load(&bg_thread, memory_order_relaxed) == 0 && + atomic_exchange(&bg_thread, 1, memory_order_relaxed) == 0) { + StartBackgroundThread(); + SetSandboxingCallback(StopBackgroundThread); + } +#endif +} + + int Finalize(ThreadState *thr) { bool failed = false; @@ -411,8 +438,7 @@ int Finalize(ThreadState *thr) { // Wait for pending reports. ctx->report_mtx.Lock(); - CommonSanitizerReportMutex.Lock(); - CommonSanitizerReportMutex.Unlock(); + { ScopedErrorReportLock l; } ctx->report_mtx.Unlock(); #if !SANITIZER_GO @@ -522,6 +548,10 @@ u32 CurrentStackId(ThreadState *thr, uptr pc) { } void TraceSwitch(ThreadState *thr) { +#if !SANITIZER_GO + if (ctx->after_multithreaded_fork) + return; +#endif thr->nomalloc++; Trace *thr_trace = ThreadTrace(thr->tid); Lock l(&thr_trace->mtx); @@ -893,7 +923,8 @@ static void MemoryRangeSet(ThreadState *thr, uptr pc, uptr addr, uptr size, u64 *p1 = p; p = RoundDown(end, kPageSize); UnmapOrDie((void*)p1, (uptr)p - (uptr)p1); - MmapFixedNoReserve((uptr)p1, (uptr)p - (uptr)p1); + if (!MmapFixedNoReserve((uptr)p1, (uptr)p - (uptr)p1)) + Die(); // Set the ending. while (p < end) { *p++ = val; diff --git a/libsanitizer/tsan/tsan_rtl.h b/libsanitizer/tsan/tsan_rtl.h index 7dd9779..f97b583 100644 --- a/libsanitizer/tsan/tsan_rtl.h +++ b/libsanitizer/tsan/tsan_rtl.h @@ -32,12 +32,13 @@ #include "sanitizer_common/sanitizer_libignore.h" #include "sanitizer_common/sanitizer_suppressions.h" #include "sanitizer_common/sanitizer_thread_registry.h" +#include "sanitizer_common/sanitizer_vector.h" #include "tsan_clock.h" #include "tsan_defs.h" #include "tsan_flags.h" +#include "tsan_mman.h" #include "tsan_sync.h" #include "tsan_trace.h" -#include "tsan_vector.h" #include "tsan_report.h" #include "tsan_platform.h" #include "tsan_mutexset.h" @@ -517,7 +518,9 @@ struct Context { Context(); bool initialized; +#if !SANITIZER_GO bool after_multithreaded_fork; +#endif MetaMap metamap; @@ -572,11 +575,8 @@ const char *GetObjectTypeFromTag(uptr tag); const char *GetReportHeaderFromTag(uptr tag); uptr TagFromShadowStackFrame(uptr pc); -class ScopedReport { +class ScopedReportBase { public: - explicit ScopedReport(ReportType typ, uptr tag = kExternalTagNone); - ~ScopedReport(); - void AddMemoryAccess(uptr addr, uptr external_tag, Shadow s, StackTrace stack, const MutexSet *mset); void AddStack(StackTrace stack, bool suppressable = false); @@ -591,6 +591,10 @@ class ScopedReport { const ReportDesc *GetReport() const; + protected: + ScopedReportBase(ReportType typ, uptr tag); + ~ScopedReportBase(); + private: ReportDesc *rep_; // Symbolizer makes lots of intercepted calls. If we try to process them, @@ -599,8 +603,17 @@ class ScopedReport { void AddDeadMutex(u64 id); - ScopedReport(const ScopedReport&); - void operator = (const ScopedReport&); + ScopedReportBase(const ScopedReportBase &) = delete; + void operator=(const ScopedReportBase &) = delete; +}; + +class ScopedReport : public ScopedReportBase { + public: + explicit ScopedReport(ReportType typ, uptr tag = kExternalTagNone); + ~ScopedReport(); + + private: + ScopedErrorReportLock lock_; }; ThreadContext *IsThreadStackOrTls(uptr addr, bool *is_stack); @@ -635,6 +648,10 @@ void ObtainCurrentStack(ThreadState *thr, uptr toppc, StackTraceTy *stack, ExtractTagFromStack(stack, tag); } +#define GET_STACK_TRACE_FATAL(thr, pc) \ + VarSizeStackTrace stack; \ + ObtainCurrentStack(thr, pc, &stack); \ + stack.ReverseOrder(); #if TSAN_COLLECT_STATS void StatAggregate(u64 *dst, u64 *src); @@ -688,6 +705,7 @@ void PrintCurrentStack(ThreadState *thr, uptr pc); void PrintCurrentStackSlow(uptr pc); // uses libunwind void Initialize(ThreadState *thr); +void MaybeSpawnBackgroundThread(); int Finalize(ThreadState *thr); void OnUserAlloc(ThreadState *thr, uptr pc, uptr p, uptr sz, bool write); diff --git a/libsanitizer/tsan/tsan_rtl_aarch64.S b/libsanitizer/tsan/tsan_rtl_aarch64.S index 61171d6..3d02bf2 100644 --- a/libsanitizer/tsan/tsan_rtl_aarch64.S +++ b/libsanitizer/tsan/tsan_rtl_aarch64.S @@ -6,7 +6,7 @@ #if !defined(__APPLE__) .section .bss .type __tsan_pointer_chk_guard, %object -ASM_SIZE(ASM_TSAN_SYMBOL_INTERCEPTOR(__tsan_pointer_chk_guard)) +ASM_SIZE(ASM_SYMBOL_INTERCEPTOR(__tsan_pointer_chk_guard)) __tsan_pointer_chk_guard: .zero 8 #endif @@ -51,7 +51,7 @@ _sigsetjmp$non_lazy_ptr: // original ones. ASM_HIDDEN(_Z18InitializeGuardPtrv) .global _Z18InitializeGuardPtrv -ASM_TYPE_FUNCTION(ASM_TSAN_SYMBOL_INTERCEPTOR(_Z18InitializeGuardPtrv)) +ASM_TYPE_FUNCTION(ASM_SYMBOL_INTERCEPTOR(_Z18InitializeGuardPtrv)) _Z18InitializeGuardPtrv: CFI_STARTPROC // Allocates a jmp_buf for the setjmp call. @@ -88,14 +88,14 @@ _Z18InitializeGuardPtrv: CFI_DEF_CFA (31, 0) ret CFI_ENDPROC -ASM_SIZE(ASM_TSAN_SYMBOL_INTERCEPTOR(_Z18InitializeGuardPtrv)) +ASM_SIZE(ASM_SYMBOL_INTERCEPTOR(_Z18InitializeGuardPtrv)) #endif ASM_HIDDEN(__tsan_setjmp) .comm _ZN14__interception11real_setjmpE,8,8 -.globl ASM_TSAN_SYMBOL_INTERCEPTOR(setjmp) -ASM_TYPE_FUNCTION(ASM_TSAN_SYMBOL_INTERCEPTOR(setjmp)) -ASM_TSAN_SYMBOL_INTERCEPTOR(setjmp): +.globl ASM_SYMBOL_INTERCEPTOR(setjmp) +ASM_TYPE_FUNCTION(ASM_SYMBOL_INTERCEPTOR(setjmp)) +ASM_SYMBOL_INTERCEPTOR(setjmp): CFI_STARTPROC // save env parameters for function call @@ -120,12 +120,14 @@ ASM_TSAN_SYMBOL_INTERCEPTOR(setjmp): add x0, x29, 32 eor x1, x2, x0 #else + adrp x2, ___tsan_darwin_setjmp_xor_key@page + ldr x2, [x2, ___tsan_darwin_setjmp_xor_key@pageoff] add x0, x29, 32 - mov x1, x0 + eor x1, x2, x0 #endif // call tsan interceptor - bl ASM_TSAN_SYMBOL(__tsan_setjmp) + bl ASM_SYMBOL(__tsan_setjmp) // restore env parameter mov x0, x19 @@ -148,12 +150,12 @@ ASM_TSAN_SYMBOL_INTERCEPTOR(setjmp): br x1 CFI_ENDPROC -ASM_SIZE(ASM_TSAN_SYMBOL_INTERCEPTOR(setjmp)) +ASM_SIZE(ASM_SYMBOL_INTERCEPTOR(setjmp)) .comm _ZN14__interception12real__setjmpE,8,8 -.globl ASM_TSAN_SYMBOL_INTERCEPTOR(_setjmp) -ASM_TYPE_FUNCTION(ASM_TSAN_SYMBOL_INTERCEPTOR(_setjmp)) -ASM_TSAN_SYMBOL_INTERCEPTOR(_setjmp): +.globl ASM_SYMBOL_INTERCEPTOR(_setjmp) +ASM_TYPE_FUNCTION(ASM_SYMBOL_INTERCEPTOR(_setjmp)) +ASM_SYMBOL_INTERCEPTOR(_setjmp): CFI_STARTPROC // save env parameters for function call @@ -178,12 +180,14 @@ ASM_TSAN_SYMBOL_INTERCEPTOR(_setjmp): add x0, x29, 32 eor x1, x2, x0 #else + adrp x2, ___tsan_darwin_setjmp_xor_key@page + ldr x2, [x2, ___tsan_darwin_setjmp_xor_key@pageoff] add x0, x29, 32 - mov x1, x0 + eor x1, x2, x0 #endif // call tsan interceptor - bl ASM_TSAN_SYMBOL(__tsan_setjmp) + bl ASM_SYMBOL(__tsan_setjmp) // Restore jmp_buf parameter mov x0, x19 @@ -206,12 +210,12 @@ ASM_TSAN_SYMBOL_INTERCEPTOR(_setjmp): br x1 CFI_ENDPROC -ASM_SIZE(ASM_TSAN_SYMBOL_INTERCEPTOR(_setjmp)) +ASM_SIZE(ASM_SYMBOL_INTERCEPTOR(_setjmp)) .comm _ZN14__interception14real_sigsetjmpE,8,8 -.globl ASM_TSAN_SYMBOL_INTERCEPTOR(sigsetjmp) -ASM_TYPE_FUNCTION(ASM_TSAN_SYMBOL_INTERCEPTOR(sigsetjmp)) -ASM_TSAN_SYMBOL_INTERCEPTOR(sigsetjmp): +.globl ASM_SYMBOL_INTERCEPTOR(sigsetjmp) +ASM_TYPE_FUNCTION(ASM_SYMBOL_INTERCEPTOR(sigsetjmp)) +ASM_SYMBOL_INTERCEPTOR(sigsetjmp): CFI_STARTPROC // save env parameters for function call @@ -238,12 +242,14 @@ ASM_TSAN_SYMBOL_INTERCEPTOR(sigsetjmp): add x0, x29, 32 eor x1, x2, x0 #else + adrp x2, ___tsan_darwin_setjmp_xor_key@page + ldr x2, [x2, ___tsan_darwin_setjmp_xor_key@pageoff] add x0, x29, 32 - mov x1, x0 + eor x1, x2, x0 #endif // call tsan interceptor - bl ASM_TSAN_SYMBOL(__tsan_setjmp) + bl ASM_SYMBOL(__tsan_setjmp) // restore env parameter mov w1, w20 @@ -268,13 +274,13 @@ ASM_TSAN_SYMBOL_INTERCEPTOR(sigsetjmp): #endif br x2 CFI_ENDPROC -ASM_SIZE(ASM_TSAN_SYMBOL_INTERCEPTOR(sigsetjmp)) +ASM_SIZE(ASM_SYMBOL_INTERCEPTOR(sigsetjmp)) #if !defined(__APPLE__) .comm _ZN14__interception16real___sigsetjmpE,8,8 -.globl ASM_TSAN_SYMBOL_INTERCEPTOR(__sigsetjmp) -ASM_TYPE_FUNCTION(ASM_TSAN_SYMBOL_INTERCEPTOR(__sigsetjmp)) -ASM_TSAN_SYMBOL_INTERCEPTOR(__sigsetjmp): +.globl ASM_SYMBOL_INTERCEPTOR(__sigsetjmp) +ASM_TYPE_FUNCTION(ASM_SYMBOL_INTERCEPTOR(__sigsetjmp)) +ASM_SYMBOL_INTERCEPTOR(__sigsetjmp): CFI_STARTPROC // save env parameters for function call @@ -303,7 +309,7 @@ ASM_TSAN_SYMBOL_INTERCEPTOR(__sigsetjmp): #endif // call tsan interceptor - bl ASM_TSAN_SYMBOL(__tsan_setjmp) + bl ASM_SYMBOL(__tsan_setjmp) mov w1, w20 mov x0, x19 @@ -321,12 +327,12 @@ ASM_TSAN_SYMBOL_INTERCEPTOR(__sigsetjmp): ldr x2, [x2, #:got_lo12:_ZN14__interception16real___sigsetjmpE] ldr x2, [x2] #else - adrp x2, ASM_TSAN_SYMBOL(__sigsetjmp)@page - add x2, x2, ASM_TSAN_SYMBOL(__sigsetjmp)@pageoff + adrp x2, ASM_SYMBOL(__sigsetjmp)@page + add x2, x2, ASM_SYMBOL(__sigsetjmp)@pageoff #endif br x2 CFI_ENDPROC -ASM_SIZE(ASM_TSAN_SYMBOL_INTERCEPTOR(__sigsetjmp)) +ASM_SIZE(ASM_SYMBOL_INTERCEPTOR(__sigsetjmp)) #endif #if defined(__linux__) diff --git a/libsanitizer/tsan/tsan_rtl_amd64.S b/libsanitizer/tsan/tsan_rtl_amd64.S index 4eb1ffd..34ef51c 100644 --- a/libsanitizer/tsan/tsan_rtl_amd64.S +++ b/libsanitizer/tsan/tsan_rtl_amd64.S @@ -2,7 +2,6 @@ #if defined(__x86_64__) #include "sanitizer_common/sanitizer_asm.h" -#include "cet.h" #if !defined(__APPLE__) .section .text @@ -11,10 +10,9 @@ #endif ASM_HIDDEN(__tsan_trace_switch) -.globl ASM_TSAN_SYMBOL(__tsan_trace_switch_thunk) -ASM_TSAN_SYMBOL(__tsan_trace_switch_thunk): +.globl ASM_SYMBOL(__tsan_trace_switch_thunk) +ASM_SYMBOL(__tsan_trace_switch_thunk): CFI_STARTPROC - _CET_ENDBR # Save scratch registers. push %rax CFI_ADJUST_CFA_OFFSET(8) @@ -52,7 +50,7 @@ ASM_TSAN_SYMBOL(__tsan_trace_switch_thunk): shr $4, %rsp # clear 4 lsb, align to 16 shl $4, %rsp - call ASM_TSAN_SYMBOL(__tsan_trace_switch) + call ASM_SYMBOL(__tsan_trace_switch) # Unalign stack frame back. mov %rbx, %rsp # restore the original rsp @@ -92,10 +90,9 @@ ASM_TSAN_SYMBOL(__tsan_trace_switch_thunk): CFI_ENDPROC ASM_HIDDEN(__tsan_report_race) -.globl ASM_TSAN_SYMBOL(__tsan_report_race_thunk) -ASM_TSAN_SYMBOL(__tsan_report_race_thunk): +.globl ASM_SYMBOL(__tsan_report_race_thunk) +ASM_SYMBOL(__tsan_report_race_thunk): CFI_STARTPROC - _CET_ENDBR # Save scratch registers. push %rax CFI_ADJUST_CFA_OFFSET(8) @@ -133,7 +130,7 @@ ASM_TSAN_SYMBOL(__tsan_report_race_thunk): shr $4, %rsp # clear 4 lsb, align to 16 shl $4, %rsp - call ASM_TSAN_SYMBOL(__tsan_report_race) + call ASM_SYMBOL(__tsan_report_race) # Unalign stack frame back. mov %rbx, %rsp # restore the original rsp @@ -173,25 +170,33 @@ ASM_TSAN_SYMBOL(__tsan_report_race_thunk): CFI_ENDPROC ASM_HIDDEN(__tsan_setjmp) -#if !defined(__APPLE__) +#if defined(__NetBSD__) +.comm _ZN14__interception15real___setjmp14E,8,8 +#elif !defined(__APPLE__) .comm _ZN14__interception11real_setjmpE,8,8 #endif -.globl ASM_TSAN_SYMBOL_INTERCEPTOR(setjmp) -ASM_TYPE_FUNCTION(ASM_TSAN_SYMBOL_INTERCEPTOR(setjmp)) -ASM_TSAN_SYMBOL_INTERCEPTOR(setjmp): +#if defined(__NetBSD__) +.globl ASM_SYMBOL_INTERCEPTOR(__setjmp14) +ASM_TYPE_FUNCTION(ASM_SYMBOL_INTERCEPTOR(__setjmp14)) +ASM_SYMBOL_INTERCEPTOR(__setjmp14): +#else +.globl ASM_SYMBOL_INTERCEPTOR(setjmp) +ASM_TYPE_FUNCTION(ASM_SYMBOL_INTERCEPTOR(setjmp)) +ASM_SYMBOL_INTERCEPTOR(setjmp): +#endif CFI_STARTPROC - _CET_ENDBR // save env parameter push %rdi CFI_ADJUST_CFA_OFFSET(8) CFI_REL_OFFSET(%rdi, 0) // obtain %rsp -#if defined(__FreeBSD__) +#if defined(__FreeBSD__) || defined(__NetBSD__) lea 8(%rsp), %rdi mov %rdi, %rsi #elif defined(__APPLE__) lea 16(%rsp), %rdi mov %rdi, %rsi + xorq ___tsan_darwin_setjmp_xor_key(%rip), %rsi #elif defined(__linux__) lea 16(%rsp), %rdi mov %rdi, %rsi @@ -201,39 +206,46 @@ ASM_TSAN_SYMBOL_INTERCEPTOR(setjmp): # error "Unknown platform" #endif // call tsan interceptor - call ASM_TSAN_SYMBOL(__tsan_setjmp) + call ASM_SYMBOL(__tsan_setjmp) // restore env parameter pop %rdi CFI_ADJUST_CFA_OFFSET(-8) CFI_RESTORE(%rdi) // tail jump to libc setjmp movl $0, %eax -#if !defined(__APPLE__) +#if defined(__NetBSD__) + movq _ZN14__interception15real___setjmp14E@GOTPCREL(%rip), %rdx + jmp *(%rdx) +#elif !defined(__APPLE__) movq _ZN14__interception11real_setjmpE@GOTPCREL(%rip), %rdx jmp *(%rdx) #else - jmp ASM_TSAN_SYMBOL(setjmp) + jmp ASM_SYMBOL(setjmp) #endif CFI_ENDPROC -ASM_SIZE(ASM_TSAN_SYMBOL_INTERCEPTOR(setjmp)) +#if defined(__NetBSD__) +ASM_SIZE(ASM_SYMBOL_INTERCEPTOR(__setjmp14)) +#else +ASM_SIZE(ASM_SYMBOL_INTERCEPTOR(setjmp)) +#endif .comm _ZN14__interception12real__setjmpE,8,8 -.globl ASM_TSAN_SYMBOL_INTERCEPTOR(_setjmp) -ASM_TYPE_FUNCTION(ASM_TSAN_SYMBOL_INTERCEPTOR(_setjmp)) -ASM_TSAN_SYMBOL_INTERCEPTOR(_setjmp): +.globl ASM_SYMBOL_INTERCEPTOR(_setjmp) +ASM_TYPE_FUNCTION(ASM_SYMBOL_INTERCEPTOR(_setjmp)) +ASM_SYMBOL_INTERCEPTOR(_setjmp): CFI_STARTPROC - _CET_ENDBR // save env parameter push %rdi CFI_ADJUST_CFA_OFFSET(8) CFI_REL_OFFSET(%rdi, 0) // obtain %rsp -#if defined(__FreeBSD__) +#if defined(__FreeBSD__) || defined(__NetBSD__) lea 8(%rsp), %rdi mov %rdi, %rsi #elif defined(__APPLE__) lea 16(%rsp), %rdi mov %rdi, %rsi + xorq ___tsan_darwin_setjmp_xor_key(%rip), %rsi #elif defined(__linux__) lea 16(%rsp), %rdi mov %rdi, %rsi @@ -243,7 +255,7 @@ ASM_TSAN_SYMBOL_INTERCEPTOR(_setjmp): # error "Unknown platform" #endif // call tsan interceptor - call ASM_TSAN_SYMBOL(__tsan_setjmp) + call ASM_SYMBOL(__tsan_setjmp) // restore env parameter pop %rdi CFI_ADJUST_CFA_OFFSET(-8) @@ -254,17 +266,23 @@ ASM_TSAN_SYMBOL_INTERCEPTOR(_setjmp): movq _ZN14__interception12real__setjmpE@GOTPCREL(%rip), %rdx jmp *(%rdx) #else - jmp ASM_TSAN_SYMBOL(_setjmp) + jmp ASM_SYMBOL(_setjmp) #endif CFI_ENDPROC -ASM_SIZE(ASM_TSAN_SYMBOL_INTERCEPTOR(_setjmp)) +ASM_SIZE(ASM_SYMBOL_INTERCEPTOR(_setjmp)) +#if defined(__NetBSD__) +.comm _ZN14__interception18real___sigsetjmp14E,8,8 +.globl ASM_SYMBOL_INTERCEPTOR(__sigsetjmp14) +ASM_TYPE_FUNCTION(ASM_SYMBOL_INTERCEPTOR(__sigsetjmp14)) +ASM_SYMBOL_INTERCEPTOR(__sigsetjmp14): +#else .comm _ZN14__interception14real_sigsetjmpE,8,8 -.globl ASM_TSAN_SYMBOL_INTERCEPTOR(sigsetjmp) -ASM_TYPE_FUNCTION(ASM_TSAN_SYMBOL_INTERCEPTOR(sigsetjmp)) -ASM_TSAN_SYMBOL_INTERCEPTOR(sigsetjmp): +.globl ASM_SYMBOL_INTERCEPTOR(sigsetjmp) +ASM_TYPE_FUNCTION(ASM_SYMBOL_INTERCEPTOR(sigsetjmp)) +ASM_SYMBOL_INTERCEPTOR(sigsetjmp): +#endif CFI_STARTPROC - _CET_ENDBR // save env parameter push %rdi CFI_ADJUST_CFA_OFFSET(8) @@ -277,12 +295,13 @@ ASM_TSAN_SYMBOL_INTERCEPTOR(sigsetjmp): sub $8, %rsp CFI_ADJUST_CFA_OFFSET(8) // obtain %rsp -#if defined(__FreeBSD__) +#if defined(__FreeBSD__) || defined(__NetBSD__) lea 24(%rsp), %rdi mov %rdi, %rsi #elif defined(__APPLE__) lea 32(%rsp), %rdi mov %rdi, %rsi + xorq ___tsan_darwin_setjmp_xor_key(%rip), %rsi #elif defined(__linux__) lea 32(%rsp), %rdi mov %rdi, %rsi @@ -292,7 +311,7 @@ ASM_TSAN_SYMBOL_INTERCEPTOR(sigsetjmp): # error "Unknown platform" #endif // call tsan interceptor - call ASM_TSAN_SYMBOL(__tsan_setjmp) + call ASM_SYMBOL(__tsan_setjmp) // unalign stack frame add $8, %rsp CFI_ADJUST_CFA_OFFSET(-8) @@ -306,22 +325,28 @@ ASM_TSAN_SYMBOL_INTERCEPTOR(sigsetjmp): CFI_RESTORE(%rdi) // tail jump to libc sigsetjmp movl $0, %eax -#if !defined(__APPLE__) +#if defined(__NetBSD__) + movq _ZN14__interception18real___sigsetjmp14E@GOTPCREL(%rip), %rdx + jmp *(%rdx) +#elif !defined(__APPLE__) movq _ZN14__interception14real_sigsetjmpE@GOTPCREL(%rip), %rdx jmp *(%rdx) #else - jmp ASM_TSAN_SYMBOL(sigsetjmp) + jmp ASM_SYMBOL(sigsetjmp) #endif CFI_ENDPROC -ASM_SIZE(ASM_TSAN_SYMBOL_INTERCEPTOR(sigsetjmp)) +#if defined(__NetBSD__) +ASM_SIZE(ASM_SYMBOL_INTERCEPTOR(__sigsetjmp14)) +#else +ASM_SIZE(ASM_SYMBOL_INTERCEPTOR(sigsetjmp)) +#endif -#if !defined(__APPLE__) +#if !defined(__APPLE__) && !defined(__NetBSD__) .comm _ZN14__interception16real___sigsetjmpE,8,8 -.globl ASM_TSAN_SYMBOL_INTERCEPTOR(__sigsetjmp) -ASM_TYPE_FUNCTION(ASM_TSAN_SYMBOL_INTERCEPTOR(__sigsetjmp)) -ASM_TSAN_SYMBOL_INTERCEPTOR(__sigsetjmp): +.globl ASM_SYMBOL_INTERCEPTOR(__sigsetjmp) +ASM_TYPE_FUNCTION(ASM_SYMBOL_INTERCEPTOR(__sigsetjmp)) +ASM_SYMBOL_INTERCEPTOR(__sigsetjmp): CFI_STARTPROC - _CET_ENDBR // save env parameter push %rdi CFI_ADJUST_CFA_OFFSET(8) @@ -344,7 +369,7 @@ ASM_TSAN_SYMBOL_INTERCEPTOR(__sigsetjmp): rol $0x11, %rsi #endif // call tsan interceptor - call ASM_TSAN_SYMBOL(__tsan_setjmp) + call ASM_SYMBOL(__tsan_setjmp) // unalign stack frame add $8, %rsp CFI_ADJUST_CFA_OFFSET(-8) @@ -361,11 +386,12 @@ ASM_TSAN_SYMBOL_INTERCEPTOR(__sigsetjmp): movq _ZN14__interception16real___sigsetjmpE@GOTPCREL(%rip), %rdx jmp *(%rdx) CFI_ENDPROC -ASM_SIZE(ASM_TSAN_SYMBOL_INTERCEPTOR(__sigsetjmp)) -#endif // !defined(__APPLE__) +ASM_SIZE(ASM_SYMBOL_INTERCEPTOR(__sigsetjmp)) +#endif // !defined(__APPLE__) && !defined(__NetBSD__) #if defined(__FreeBSD__) || defined(__linux__) /* We do not need executable stack. */ +/* This note is not needed on NetBSD. */ .section .note.GNU-stack,"",@progbits #endif diff --git a/libsanitizer/tsan/tsan_rtl_mutex.cc b/libsanitizer/tsan/tsan_rtl_mutex.cc index d10a873..6981f98 100644 --- a/libsanitizer/tsan/tsan_rtl_mutex.cc +++ b/libsanitizer/tsan/tsan_rtl_mutex.cc @@ -82,7 +82,9 @@ void MutexDestroy(ThreadState *thr, uptr pc, uptr addr, u32 flagz) { SyncVar *s = ctx->metamap.GetIfExistsAndLock(addr, true); if (s == 0) return; - if ((flagz & MutexFlagLinkerInit) || s->IsFlagSet(MutexFlagLinkerInit)) { + if ((flagz & MutexFlagLinkerInit) + || s->IsFlagSet(MutexFlagLinkerInit) + || ((flagz & MutexFlagNotStatic) && !s->IsFlagSet(MutexFlagNotStatic))) { // Destroy is no-op for linker-initialized mutexes. s->mtx.Unlock(); return; @@ -100,7 +102,7 @@ void MutexDestroy(ThreadState *thr, uptr pc, uptr addr, u32 flagz) { unlock_locked = true; } u64 mid = s->GetId(); - u32 last_lock = s->last_lock; + u64 last_lock = s->last_lock; if (!unlock_locked) s->Reset(thr->proc()); // must not reset it before the report is printed s->mtx.Unlock(); @@ -110,7 +112,7 @@ void MutexDestroy(ThreadState *thr, uptr pc, uptr addr, u32 flagz) { rep.AddMutex(mid); VarSizeStackTrace trace; ObtainCurrentStack(thr, pc, &trace); - rep.AddStack(trace); + rep.AddStack(trace, true); FastState last(last_lock); RestoreStack(last.tid(), last.epoch(), &trace, 0); rep.AddStack(trace, true); @@ -357,7 +359,7 @@ void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) { if (s->recursion == 0) { StatInc(thr, StatMutexUnlock); s->owner_tid = SyncVar::kInvalidTid; - ReleaseImpl(thr, pc, &s->clock); + ReleaseStoreImpl(thr, pc, &s->clock); } else { StatInc(thr, StatMutexRecUnlock); } diff --git a/libsanitizer/tsan/tsan_rtl_report.cc b/libsanitizer/tsan/tsan_rtl_report.cc index a961139..18b6cf7 100644 --- a/libsanitizer/tsan/tsan_rtl_report.cc +++ b/libsanitizer/tsan/tsan_rtl_report.cc @@ -141,30 +141,28 @@ static ReportStack *SymbolizeStack(StackTrace trace) { return stack; } -ScopedReport::ScopedReport(ReportType typ, uptr tag) { +ScopedReportBase::ScopedReportBase(ReportType typ, uptr tag) { ctx->thread_registry->CheckLocked(); void *mem = internal_alloc(MBlockReport, sizeof(ReportDesc)); rep_ = new(mem) ReportDesc; rep_->typ = typ; rep_->tag = tag; ctx->report_mtx.Lock(); - CommonSanitizerReportMutex.Lock(); } -ScopedReport::~ScopedReport() { - CommonSanitizerReportMutex.Unlock(); +ScopedReportBase::~ScopedReportBase() { ctx->report_mtx.Unlock(); DestroyAndFree(rep_); } -void ScopedReport::AddStack(StackTrace stack, bool suppressable) { +void ScopedReportBase::AddStack(StackTrace stack, bool suppressable) { ReportStack **rs = rep_->stacks.PushBack(); *rs = SymbolizeStack(stack); (*rs)->suppressable = suppressable; } -void ScopedReport::AddMemoryAccess(uptr addr, uptr external_tag, Shadow s, - StackTrace stack, const MutexSet *mset) { +void ScopedReportBase::AddMemoryAccess(uptr addr, uptr external_tag, Shadow s, + StackTrace stack, const MutexSet *mset) { void *mem = internal_alloc(MBlockReportMop, sizeof(ReportMop)); ReportMop *mop = new(mem) ReportMop; rep_->mops.PushBack(mop); @@ -185,11 +183,11 @@ void ScopedReport::AddMemoryAccess(uptr addr, uptr external_tag, Shadow s, } } -void ScopedReport::AddUniqueTid(int unique_tid) { +void ScopedReportBase::AddUniqueTid(int unique_tid) { rep_->unique_tids.PushBack(unique_tid); } -void ScopedReport::AddThread(const ThreadContext *tctx, bool suppressable) { +void ScopedReportBase::AddThread(const ThreadContext *tctx, bool suppressable) { for (uptr i = 0; i < rep_->threads.Size(); i++) { if ((u32)rep_->threads[i]->id == tctx->tid) return; @@ -253,14 +251,14 @@ ThreadContext *IsThreadStackOrTls(uptr addr, bool *is_stack) { } #endif -void ScopedReport::AddThread(int unique_tid, bool suppressable) { +void ScopedReportBase::AddThread(int unique_tid, bool suppressable) { #if !SANITIZER_GO if (const ThreadContext *tctx = FindThreadByUidLocked(unique_tid)) AddThread(tctx, suppressable); #endif } -void ScopedReport::AddMutex(const SyncVar *s) { +void ScopedReportBase::AddMutex(const SyncVar *s) { for (uptr i = 0; i < rep_->mutexes.Size(); i++) { if (rep_->mutexes[i]->id == s->uid) return; @@ -274,7 +272,7 @@ void ScopedReport::AddMutex(const SyncVar *s) { rm->stack = SymbolizeStackId(s->creation_stack_id); } -u64 ScopedReport::AddMutex(u64 id) { +u64 ScopedReportBase::AddMutex(u64 id) { u64 uid = 0; u64 mid = id; uptr addr = SyncVar::SplitId(id, &uid); @@ -293,7 +291,7 @@ u64 ScopedReport::AddMutex(u64 id) { return mid; } -void ScopedReport::AddDeadMutex(u64 id) { +void ScopedReportBase::AddDeadMutex(u64 id) { for (uptr i = 0; i < rep_->mutexes.Size(); i++) { if (rep_->mutexes[i]->id == id) return; @@ -307,7 +305,7 @@ void ScopedReport::AddDeadMutex(u64 id) { rm->stack = 0; } -void ScopedReport::AddLocation(uptr addr, uptr size) { +void ScopedReportBase::AddLocation(uptr addr, uptr size) { if (addr == 0) return; #if !SANITIZER_GO @@ -362,18 +360,19 @@ void ScopedReport::AddLocation(uptr addr, uptr size) { } #if !SANITIZER_GO -void ScopedReport::AddSleep(u32 stack_id) { +void ScopedReportBase::AddSleep(u32 stack_id) { rep_->sleep = SymbolizeStackId(stack_id); } #endif -void ScopedReport::SetCount(int count) { - rep_->count = count; -} +void ScopedReportBase::SetCount(int count) { rep_->count = count; } -const ReportDesc *ScopedReport::GetReport() const { - return rep_; -} +const ReportDesc *ScopedReportBase::GetReport() const { return rep_; } + +ScopedReport::ScopedReport(ReportType typ, uptr tag) + : ScopedReportBase(typ, tag) {} + +ScopedReport::~ScopedReport() {} void RestoreStack(int tid, const u64 epoch, VarSizeStackTrace *stk, MutexSet *mset, uptr *tag) { @@ -392,7 +391,7 @@ void RestoreStack(int tid, const u64 epoch, VarSizeStackTrace *stk, const u64 ebegin = RoundDown(eend, kTracePartSize); DPrintf("#%d: RestoreStack epoch=%zu ebegin=%zu eend=%zu partidx=%d\n", tid, (uptr)epoch, (uptr)ebegin, (uptr)eend, partidx); - Vector<uptr> stack(MBlockReportStack); + Vector<uptr> stack; stack.Resize(hdr->stack0.size + 64); for (uptr i = 0; i < hdr->stack0.size; i++) { stack[i] = hdr->stack0.trace[i]; @@ -648,8 +647,8 @@ void ReportRace(ThreadState *thr) { // callback. Most likely, TraceTopPC will now return a EventTypeFuncExit // event. Later we subtract -1 from it (in GetPreviousInstructionPc) // and the resulting PC has kExternalPCBit set, so we pass it to - // __tsan_symbolize_external. __tsan_symbolize_external is within its rights - // to crash since the PC is completely bogus. + // __tsan_symbolize_external_ex. __tsan_symbolize_external_ex is within its + // rights to crash since the PC is completely bogus. // test/tsan/double_race.cc contains a test case for this. toppc = 0; } @@ -658,7 +657,7 @@ void ReportRace(ThreadState *thr) { return; // MutexSet is too large to live on stack. - Vector<u64> mset_buffer(MBlockScopedBuf); + Vector<u64> mset_buffer; mset_buffer.Resize(sizeof(MutexSet) / sizeof(u64) + 1); MutexSet *mset2 = new(&mset_buffer[0]) MutexSet(); diff --git a/libsanitizer/tsan/tsan_rtl_thread.cc b/libsanitizer/tsan/tsan_rtl_thread.cc index e81669d..7a731c4 100644 --- a/libsanitizer/tsan/tsan_rtl_thread.cc +++ b/libsanitizer/tsan/tsan_rtl_thread.cc @@ -209,7 +209,7 @@ void ThreadFinalize(ThreadState *thr) { if (!flags()->report_thread_leaks) return; ThreadRegistryLock l(ctx->thread_registry); - Vector<ThreadLeak> leaks(MBlockScopedBuf); + Vector<ThreadLeak> leaks; ctx->thread_registry->RunCallbackForEachThreadLocked( MaybeReportThreadLeak, &leaks); for (uptr i = 0; i < leaks.Size(); i++) { diff --git a/libsanitizer/tsan/tsan_stack_trace.cc b/libsanitizer/tsan/tsan_stack_trace.cc index 3734e0e..4ddec96 100644 --- a/libsanitizer/tsan/tsan_stack_trace.cc +++ b/libsanitizer/tsan/tsan_stack_trace.cc @@ -41,4 +41,9 @@ void VarSizeStackTrace::Init(const uptr *pcs, uptr cnt, uptr extra_top_pc) { trace_buffer[cnt] = extra_top_pc; } +void VarSizeStackTrace::ReverseOrder() { + for (u32 i = 0; i < (size >> 1); i++) + Swap(trace_buffer[i], trace_buffer[size - 1 - i]); +} + } // namespace __tsan diff --git a/libsanitizer/tsan/tsan_stack_trace.h b/libsanitizer/tsan/tsan_stack_trace.h index b097a9b..bc4468f 100644 --- a/libsanitizer/tsan/tsan_stack_trace.h +++ b/libsanitizer/tsan/tsan_stack_trace.h @@ -25,6 +25,10 @@ struct VarSizeStackTrace : public StackTrace { ~VarSizeStackTrace(); void Init(const uptr *pcs, uptr cnt, uptr extra_top_pc = 0); + // Reverses the current stack trace order, the top frame goes to the bottom, + // the last frame goes to the top. + void ReverseOrder(); + private: void ResizeBuffer(uptr new_size); diff --git a/libsanitizer/tsan/tsan_suppressions.cc b/libsanitizer/tsan/tsan_suppressions.cc index e40eb70..d48148f 100644 --- a/libsanitizer/tsan/tsan_suppressions.cc +++ b/libsanitizer/tsan/tsan_suppressions.cc @@ -150,7 +150,7 @@ uptr IsSuppressed(ReportType typ, const ReportLocation *loc, Suppression **sp) { } void PrintMatchedSuppressions() { - InternalMmapVector<Suppression *> matched(1); + InternalMmapVector<Suppression *> matched; CHECK(suppression_ctx); suppression_ctx->GetMatched(&matched); if (!matched.size()) diff --git a/libsanitizer/tsan/tsan_symbolize.cc b/libsanitizer/tsan/tsan_symbolize.cc index 7b04782..074006b 100644 --- a/libsanitizer/tsan/tsan_symbolize.cc +++ b/libsanitizer/tsan/tsan_symbolize.cc @@ -34,6 +34,7 @@ void ExitSymbolizer() { thr->ignore_interceptors--; } +// Legacy API. // May be overriden by JIT/JAVA/etc, // whatever produces PCs marked with kExternalPCBit. SANITIZER_WEAK_DEFAULT_IMPL @@ -43,9 +44,49 @@ bool __tsan_symbolize_external(uptr pc, char *func_buf, uptr func_siz, return false; } +// New API: call __tsan_symbolize_external_ex only when it exists. +// Once old clients are gone, provide dummy implementation. +SANITIZER_WEAK_DEFAULT_IMPL +void __tsan_symbolize_external_ex(uptr pc, + void (*add_frame)(void *, const char *, + const char *, int, int), + void *ctx) {} + +struct SymbolizedStackBuilder { + SymbolizedStack *head; + SymbolizedStack *tail; + uptr addr; +}; + +static void AddFrame(void *ctx, const char *function_name, const char *file, + int line, int column) { + SymbolizedStackBuilder *ssb = (struct SymbolizedStackBuilder *)ctx; + if (ssb->tail) { + ssb->tail->next = SymbolizedStack::New(ssb->addr); + ssb->tail = ssb->tail->next; + } else { + ssb->head = ssb->tail = SymbolizedStack::New(ssb->addr); + } + AddressInfo *info = &ssb->tail->info; + if (function_name) { + info->function = internal_strdup(function_name); + } + if (file) { + info->file = internal_strdup(file); + } + info->line = line; + info->column = column; +} + SymbolizedStack *SymbolizeCode(uptr addr) { // Check if PC comes from non-native land. if (addr & kExternalPCBit) { + SymbolizedStackBuilder ssb = {nullptr, nullptr, addr}; + __tsan_symbolize_external_ex(addr, AddFrame, &ssb); + if (ssb.head) + return ssb.head; + // Legacy code: remove along with the declaration above + // once all clients using this API are gone. // Declare static to not consume too much stack space. // We symbolize reports in a single thread, so this is fine. static char func_buf[1024]; diff --git a/libsanitizer/tsan/tsan_sync.cc b/libsanitizer/tsan/tsan_sync.cc index 0f840de..10ae446 100644 --- a/libsanitizer/tsan/tsan_sync.cc +++ b/libsanitizer/tsan/tsan_sync.cc @@ -174,7 +174,8 @@ void MetaMap::ResetRange(Processor *proc, uptr p, uptr sz) { uptr metap = (uptr)MemToMeta(p0); uptr metasz = sz0 / kMetaRatio; UnmapOrDie((void*)metap, metasz); - MmapFixedNoReserve(metap, metasz); + if (!MmapFixedNoReserve(metap, metasz)) + Die(); } MBlock* MetaMap::GetBlock(uptr p) { diff --git a/libsanitizer/tsan/tsan_sync.h b/libsanitizer/tsan/tsan_sync.h index 195279f..a4409fe 100644 --- a/libsanitizer/tsan/tsan_sync.h +++ b/libsanitizer/tsan/tsan_sync.h @@ -32,6 +32,7 @@ enum MutexFlags { MutexFlagTryLockFailed = 1 << 5, // __tsan_mutex_try_lock_failed MutexFlagRecursiveLock = 1 << 6, // __tsan_mutex_recursive_lock MutexFlagRecursiveUnlock = 1 << 7, // __tsan_mutex_recursive_unlock + MutexFlagNotStatic = 1 << 8, // __tsan_mutex_not_static // The following flags are runtime private. // Mutex API misuse was detected, so don't report any more. @@ -41,7 +42,8 @@ enum MutexFlags { // Must list all mutex creation flags. MutexCreationFlagMask = MutexFlagLinkerInit | MutexFlagWriteReentrant | - MutexFlagReadReentrant, + MutexFlagReadReentrant | + MutexFlagNotStatic, }; struct SyncVar { diff --git a/libsanitizer/tsan/tsan_vector.h b/libsanitizer/tsan/tsan_vector.h deleted file mode 100644 index c048551..0000000 --- a/libsanitizer/tsan/tsan_vector.h +++ /dev/null @@ -1,125 +0,0 @@ -//===-- tsan_vector.h -------------------------------------------*- C++ -*-===// -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file is a part of ThreadSanitizer (TSan), a race detector. -// -//===----------------------------------------------------------------------===// - -// Low-fat STL-like vector container. - -#ifndef TSAN_VECTOR_H -#define TSAN_VECTOR_H - -#include "tsan_defs.h" -#include "tsan_mman.h" - -namespace __tsan { - -template<typename T> -class Vector { - public: - explicit Vector(MBlockType typ) - : typ_(typ) - , begin_() - , end_() - , last_() { - } - - ~Vector() { - if (begin_) - internal_free(begin_); - } - - void Reset() { - if (begin_) - internal_free(begin_); - begin_ = 0; - end_ = 0; - last_ = 0; - } - - uptr Size() const { - return end_ - begin_; - } - - T &operator[](uptr i) { - DCHECK_LT(i, end_ - begin_); - return begin_[i]; - } - - const T &operator[](uptr i) const { - DCHECK_LT(i, end_ - begin_); - return begin_[i]; - } - - T *PushBack() { - EnsureSize(Size() + 1); - T *p = &end_[-1]; - internal_memset(p, 0, sizeof(*p)); - return p; - } - - T *PushBack(const T& v) { - EnsureSize(Size() + 1); - T *p = &end_[-1]; - internal_memcpy(p, &v, sizeof(*p)); - return p; - } - - void PopBack() { - DCHECK_GT(end_, begin_); - end_--; - } - - void Resize(uptr size) { - if (size == 0) { - end_ = begin_; - return; - } - uptr old_size = Size(); - EnsureSize(size); - if (old_size < size) { - for (uptr i = old_size; i < size; i++) - internal_memset(&begin_[i], 0, sizeof(begin_[i])); - } - } - - private: - const MBlockType typ_; - T *begin_; - T *end_; - T *last_; - - void EnsureSize(uptr size) { - if (size <= Size()) - return; - if (size <= (uptr)(last_ - begin_)) { - end_ = begin_ + size; - return; - } - uptr cap0 = last_ - begin_; - uptr cap = cap0 * 5 / 4; // 25% growth - if (cap == 0) - cap = 16; - if (cap < size) - cap = size; - T *p = (T*)internal_alloc(typ_, cap * sizeof(T)); - if (cap0) { - internal_memcpy(p, begin_, cap0 * sizeof(T)); - internal_free(begin_); - } - begin_ = p; - end_ = begin_ + size; - last_ = begin_ + cap; - } - - Vector(const Vector&); - void operator=(const Vector&); -}; -} // namespace __tsan - -#endif // #ifndef TSAN_VECTOR_H |