From 0bd785584ef24b84dad0bc44d2034616c43ce967 Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Fri, 3 Nov 2017 20:39:51 +0000 Subject: Disable detection of on_exit()/TSan on NetBSD Summary: NetBSD does not ship with on_exit() function. Introduce TSAN_MAYBE_INTERCEPT_ON_EXIT. It looks like this addition fixes build for Darwin. Sponsored by Reviewers: vitalybuka, joerg, eugenis, dvyukov, kcc Reviewed By: vitalybuka Subscribers: llvm-commits, kubamracek, #sanitizers Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D39617 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@317361 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/rtl/tsan_interceptors.cc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'lib/tsan') diff --git a/lib/tsan/rtl/tsan_interceptors.cc b/lib/tsan/rtl/tsan_interceptors.cc index 79e243aef..9fbfef52c 100644 --- a/lib/tsan/rtl/tsan_interceptors.cc +++ b/lib/tsan/rtl/tsan_interceptors.cc @@ -435,7 +435,7 @@ static int setup_at_exit_wrapper(ThreadState *thr, uptr pc, void(*f)(), 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; @@ -460,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. @@ -2605,7 +2608,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); -- cgit v1.2.1 From aad2b2b91309ddb2f05cb2c5e3ea3a24ac3684b9 Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Fri, 3 Nov 2017 20:48:19 +0000 Subject: Correct detection of a thread termination Summary: Stop using the Linux solution with pthread_key_create(3). This approach does not work on NetBSD, because calling the thread destructor is not the latest operation on a POSIX thread entity. NetBSD's libpthread still calls at least pthread_mutex_lock and pthread_mutex_unlock. Detect _lwp_exit(2) call as it is really the latest operation called from a detaching POSIX thread. This resolves one set of crashes observed in the Thread Sanitizer execution. Sponsored by Reviewers: joerg, kcc, vitalybuka, dvyukov, eugenis Reviewed By: vitalybuka Subscribers: llvm-commits, kubamracek, #sanitizers Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D39618 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@317363 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/rtl/tsan_interceptors.cc | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) (limited to 'lib/tsan') diff --git a/lib/tsan/rtl/tsan_interceptors.cc b/lib/tsan/rtl/tsan_interceptors.cc index 9fbfef52c..db92f7528 100644 --- a/lib/tsan/rtl/tsan_interceptors.cc +++ b/lib/tsan/rtl/tsan_interceptors.cc @@ -265,7 +265,7 @@ static ThreadSignalContext *SigCtx(ThreadState *thr) { return ctx; } -#if !SANITIZER_MAC +#if !SANITIZER_MAC && !SANITIZER_NETBSD static unsigned g_thread_finalize_key; #endif @@ -869,7 +869,7 @@ void DestroyThreadState() { } } // namespace __tsan -#if !SANITIZER_MAC +#if !SANITIZER_MAC && !SANITIZER_NETBSD static void thread_finalize(void *v) { uptr iter = (uptr)v; if (iter > 1) { @@ -899,7 +899,7 @@ 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 ThreadIgnoreBegin(thr, 0); if (pthread_setspecific(g_thread_finalize_key, (void *)GetPthreadDestructorIterations())) { @@ -2448,6 +2448,17 @@ TSAN_INTERCEPTOR(void *, __tls_get_addr, void *arg) { } #endif +#if SANITIZER_NETBSD +TSAN_INTERCEPTOR(void, _lwp_exit) { + SCOPED_TSAN_INTERCEPTOR(_lwp_exit); + REAL(_lwp_exit)(); + DestroyThreadState(); +} +#define TSAN_MAYBE_INTERCEPT__LWP_EXIT TSAN_INTERCEPT(_lwp_exit) +#else +#define TSAN_MAYBE_INTERCEPT__LWP_EXIT +#endif + namespace __tsan { static void finalize(void *arg) { @@ -2616,6 +2627,8 @@ void InitializeInterceptors() { TSAN_INTERCEPT(__tls_get_addr); #endif + TSAN_MAYBE_INTERCEPT__LWP_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. @@ -2627,7 +2640,7 @@ void InitializeInterceptors() { Die(); } -#if !SANITIZER_MAC +#if !SANITIZER_MAC && !SANITIZER_NETBSD if (pthread_key_create(&g_thread_finalize_key, &thread_finalize)) { Printf("ThreadSanitizer: failed to create thread key\n"); Die(); -- cgit v1.2.1 From ef40253e3d57a0398fa52dc371c11f383192235f Mon Sep 17 00:00:00 2001 From: Kamil Rytarowski Date: Fri, 3 Nov 2017 21:08:52 +0000 Subject: Late fixup in _lwp_exit on TSan/NetBSD Call DestroyThreadState() before REAL(_lwp_exit)(); This variation is less racy. Sponsored by git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@317369 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/rtl/tsan_interceptors.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/tsan') diff --git a/lib/tsan/rtl/tsan_interceptors.cc b/lib/tsan/rtl/tsan_interceptors.cc index db92f7528..0b4e873a0 100644 --- a/lib/tsan/rtl/tsan_interceptors.cc +++ b/lib/tsan/rtl/tsan_interceptors.cc @@ -2451,8 +2451,8 @@ TSAN_INTERCEPTOR(void *, __tls_get_addr, void *arg) { #if SANITIZER_NETBSD TSAN_INTERCEPTOR(void, _lwp_exit) { SCOPED_TSAN_INTERCEPTOR(_lwp_exit); - REAL(_lwp_exit)(); DestroyThreadState(); + REAL(_lwp_exit)(); } #define TSAN_MAYBE_INTERCEPT__LWP_EXIT TSAN_INTERCEPT(_lwp_exit) #else -- cgit v1.2.1 From 5df11b04709468c4b4ce5c7ed0308eb127023a52 Mon Sep 17 00:00:00 2001 From: Mehdi Amini Date: Sat, 4 Nov 2017 00:07:20 +0000 Subject: Fix CMake definitions of tsan runtime to make it installed by "install-compiler-rt" Summary: The PARENT_TARGET was correctly set under APPLE but not under linux. Reviewers: kubamracek, samsonov Subscribers: dberris, mgorny, llvm-commits Differential Revision: https://reviews.llvm.org/D39621 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@317391 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/CMakeLists.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'lib/tsan') diff --git a/lib/tsan/CMakeLists.txt b/lib/tsan/CMakeLists.txt index 08974a467..f7a5d70a3 100644 --- a/lib/tsan/CMakeLists.txt +++ b/lib/tsan/CMakeLists.txt @@ -184,13 +184,15 @@ else() $ $ $ - CFLAGS ${TSAN_RTL_CFLAGS}) + CFLAGS ${TSAN_RTL_CFLAGS} + PARENT_TARGET tsan) add_compiler_rt_runtime(clang_rt.tsan_cxx STATIC ARCHS ${arch} SOURCES ${TSAN_CXX_SOURCES} $ - CFLAGS ${TSAN_RTL_CFLAGS}) + CFLAGS ${TSAN_RTL_CFLAGS} + PARENT_TARGET tsan) list(APPEND TSAN_RUNTIME_LIBRARIES clang_rt.tsan-${arch} clang_rt.tsan_cxx-${arch}) add_sanitizer_rt_symbols(clang_rt.tsan -- cgit v1.2.1 From 2e68a0aaed73455ccf62d0a4bced2aad8c3f1c3f Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Tue, 7 Nov 2017 16:31:08 +0000 Subject: tsan: allow usage of global vars with ctors in interceptors We allow usage of global/per-thread data with non-trivial ctors/dtors throughout tsan code base by placing all global/per-thread data into Context/ThreadState and then explicitly constructing them with placement new. This greatly simplifies code by restricting the "linker initialized plague" to only these 2 objects. Do the same for interceptors data. This allows to use Vector instead of bunch of hand-written code in: https://reviews.llvm.org/D39619 Reviewed in: https://reviews.llvm.org/D39721 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@317587 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/rtl/tsan_interceptors.cc | 45 ++++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 13 deletions(-) (limited to 'lib/tsan') diff --git a/lib/tsan/rtl/tsan_interceptors.cc b/lib/tsan/rtl/tsan_interceptors.cc index 0b4e873a0..976fe2967 100644 --- a/lib/tsan/rtl/tsan_interceptors.cc +++ b/lib/tsan/rtl/tsan_interceptors.cc @@ -213,8 +213,6 @@ 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; @@ -233,11 +231,31 @@ 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)]; +// 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; + sigaction_t sigactions[kSigCount]; +#if !SANITIZER_MAC && !SANITIZER_NETBSD + unsigned finalize_key; +#endif + + InterceptorContext() + : libignore(LINKER_INITIALIZED) { + } +}; + +static ALIGNED(64) char interceptor_placeholder[sizeof(InterceptorContext)]; +InterceptorContext *interceptor_ctx() { + return reinterpret_cast(&interceptor_placeholder[0]); +} + LibIgnore *libignore() { - return reinterpret_cast(&libignore_placeholder[0]); + return &interceptor_ctx()->libignore; } void InitializeLibIgnore() { @@ -265,10 +283,6 @@ static ThreadSignalContext *SigCtx(ThreadState *thr) { return ctx; } -#if !SANITIZER_MAC && !SANITIZER_NETBSD -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) { @@ -873,7 +887,8 @@ void DestroyThreadState() { 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(); } @@ -901,7 +916,7 @@ extern "C" void *__tsan_thread_start_func(void *arg) { ScopedIgnoreInterceptors ignore; #if !SANITIZER_MAC && !SANITIZER_NETBSD 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(); @@ -1802,6 +1817,7 @@ namespace __tsan { static void CallUserSignalHandler(ThreadState *thr, bool sync, bool acquire, bool sigact, int sig, my_siginfo_t *info, void *uctx) { + sigaction_t *sigactions = interceptor_ctx()->sigactions; if (acquire) Acquire(thr, 0, (uptr)&sigactions[sig]); // Signals are generally asynchronous, so if we receive a signals when @@ -1953,6 +1969,7 @@ TSAN_INTERCEPTOR(int, sigaction, int sig, sigaction_t *act, sigaction_t *old) { // 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); + sigaction_t *sigactions = interceptor_ctx()->sigactions; if (old) internal_memcpy(old, &sigactions[sig], sizeof(*old)); if (act == 0) @@ -2490,6 +2507,8 @@ void InitializeInterceptors() { mallopt(-3, 32*1024); // M_MMAP_THRESHOLD #endif + new(interceptor_ctx()) InterceptorContext(); + InitializeCommonInterceptors(); #if !SANITIZER_MAC @@ -2641,7 +2660,7 @@ void InitializeInterceptors() { } #if !SANITIZER_MAC && !SANITIZER_NETBSD - if (pthread_key_create(&g_thread_finalize_key, &thread_finalize)) { + if (pthread_key_create(&interceptor_ctx()->finalize_key, &thread_finalize)) { Printf("ThreadSanitizer: failed to create thread key\n"); Die(); } -- cgit v1.2.1 From c58a938aae7ebeaa26c4552fe4c4586c28dbf1ff Mon Sep 17 00:00:00 2001 From: Evgeniy Stepanov Date: Tue, 7 Nov 2017 23:51:22 +0000 Subject: (NFC) Rename GetMax{,User}VirtualAddress. Future change will introduce GetMaxVirtualAddress that will not take the kernel area into account. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@317638 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/tsan/rtl/tsan_platform_mac.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/tsan') diff --git a/lib/tsan/rtl/tsan_platform_mac.cc b/lib/tsan/rtl/tsan_platform_mac.cc index 4570286b1..f8d7324b7 100644 --- a/lib/tsan/rtl/tsan_platform_mac.cc +++ b/lib/tsan/rtl/tsan_platform_mac.cc @@ -231,7 +231,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); -- cgit v1.2.1