Index: sanitizer_common/CMakeLists.txt =================================================================== --- sanitizer_common/CMakeLists.txt +++ sanitizer_common/CMakeLists.txt @@ -6,6 +6,7 @@ sanitizer_common.cc sanitizer_flags.cc sanitizer_libc.cc + sanitizer_libignore.cc sanitizer_linux.cc sanitizer_mac.cc sanitizer_platform_limits_linux.cc @@ -44,6 +45,7 @@ sanitizer_internal_defs.h sanitizer_lfstack.h sanitizer_libc.h + sanitizer_libignore.h sanitizer_linux.h sanitizer_list.h sanitizer_mutex.h Index: sanitizer_common/sanitizer_libignore.h =================================================================== --- sanitizer_common/sanitizer_libignore.h +++ sanitizer_common/sanitizer_libignore.h @@ -0,0 +1,82 @@ +//===-- sanitizer_libignore.h -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// LibIgnore allows to ignore all interceptors called from a particular set +// of dynamic libraries. LibIgnore remembers all "called_from_lib" suppressions +// from the provided SuppressionContext; finds code ranges for the libraries; +// and checks whether the provided PC value belongs to the code ranges. +// +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_LIBIGNORE_H +#define SANITIZER_LIBIGNORE_H + +#include "sanitizer_internal_defs.h" +#include "sanitizer_common.h" +#include "sanitizer_suppressions.h" +#include "sanitizer_atomic.h" +#include "sanitizer_mutex.h" + +namespace __sanitizer { + +class LibIgnore { + public: + explicit LibIgnore(LinkerInitialized); + + // Fetches all "called_from_lib" suppressions from the SuppressionContext. + void Init(const SuppressionContext &supp); + + // Must be called after a new dynamic library is loaded. + void OnLibraryLoaded(); + + // Must be called after a dynamic library is unloaded. + void OnLibraryUnloaded(); + + // Checks whether the provided PC belongs to one of the ignored libraries. + bool IsIgnored(uptr pc) const; + + private: + struct Lib { + char *templ; + char *name; + bool loaded; + }; + + struct LibCodeRange { + uptr begin; + uptr end; + }; + + static const uptr kMaxLibs = 128; + + // Hot part: + atomic_uintptr_t loaded_count_; + LibCodeRange code_ranges_[kMaxLibs]; + + // Cold part: + BlockingMutex mutex_; + uptr count_; + Lib libs_[kMaxLibs]; + + LibIgnore(const LibIgnore&); // not implemented + void operator = (const LibIgnore&); // not implemented +}; + +inline bool LibIgnore::IsIgnored(uptr pc) const { + const uptr n = atomic_load(&loaded_count_, memory_order_acquire); + for (uptr i = 0; i < n; i++) { + if (pc >= code_ranges_[i].begin && pc < code_ranges_[i].end) + return true; + } + return false; +} + +} // namespace __sanitizer + +#endif // SANITIZER_LIBIGNORE_H Index: sanitizer_common/sanitizer_libignore.cc =================================================================== --- sanitizer_common/sanitizer_libignore.cc +++ sanitizer_common/sanitizer_libignore.cc @@ -0,0 +1,85 @@ +//===-- sanitizer_libignore.cc --------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#if SANITIZER_LINUX + +#include "sanitizer_libignore.h" +#include "sanitizer_procmaps.h" + +namespace __sanitizer { + +LibIgnore::LibIgnore(LinkerInitialized) { +} + +void LibIgnore::Init(const SuppressionContext &supp) { + BlockingMutexLock lock(&mutex_); + CHECK_EQ(count_, 0); + const uptr n = supp.SuppressionCount(); + for (uptr i = 0; i < n; i++) { + const Suppression *s = supp.SuppressionAt(i); + if (s->type != SuppressionLib) + continue; + if (count_ >= kMaxLibs) { + Report("%s: too many called_from_lib suppressions (max: %d)\n", + SanitizerToolName, kMaxLibs); + Die(); + } + Lib *lib = &libs_[count_++]; + lib->templ = internal_strdup(s->templ); + lib->name = 0; + lib->loaded = false; + } +} + +void LibIgnore::OnLibraryLoaded() { + BlockingMutexLock lock(&mutex_); + MemoryMappingLayout proc_maps(/*cache_enabled*/false); + InternalScopedBuffer fn(4096); + for (uptr i = 0; i < count_; i++) { + Lib *lib = &libs_[i]; + bool loaded = false; + proc_maps.Reset(); + uptr b, e, off, prot; + while (proc_maps.Next(&b, &e, &off, fn.data(), fn.size(), &prot)) { + if ((prot & MemoryMappingLayout::kProtectionExecute) != 0 && + TemplateMatch(lib->templ, fn.data())) { + if (loaded) { + Report("%s: called_from_lib suppression '%s' is matched against" + " 2 libraries: '%s' and '%s'\n", + SanitizerToolName, lib->templ, lib->name, fn.data()); + Die(); + } + loaded = true; + if (!lib->loaded) { + lib->loaded = true; + lib->name = internal_strdup(fn.data()); + const uptr idx = atomic_load(&loaded_count_, memory_order_relaxed); + code_ranges_[idx].begin = b; + code_ranges_[idx].end = e; + atomic_store(&loaded_count_, idx + 1, memory_order_release); + } + } + } + if (lib->loaded && !loaded) { + Report("%s: library '%s' that was matched against called_from_lib" + " suppression '%s' is unloaded\n", + SanitizerToolName, lib->name, lib->templ); + Die(); + } + } +} + +void LibIgnore::OnLibraryUnloaded() { + OnLibraryLoaded(); +} + +} // namespace __sanitizer + +#endif // #if SANITIZER_LINUX Index: sanitizer_common/sanitizer_suppressions.h =================================================================== --- sanitizer_common/sanitizer_suppressions.h +++ sanitizer_common/sanitizer_suppressions.h @@ -25,6 +25,7 @@ SuppressionThread, SuppressionSignal, SuppressionLeak, + SuppressionLib, SuppressionTypeCount }; @@ -40,7 +41,8 @@ SuppressionContext() : suppressions_(1), can_parse_(true) {} void Parse(const char *str); bool Match(const char* str, SuppressionType type, Suppression **s); - uptr SuppressionCount(); + uptr SuppressionCount() const; + const Suppression *SuppressionAt(uptr i) const; void GetMatched(InternalMmapVector *matched); private: @@ -52,7 +54,6 @@ const char *SuppressionTypeString(SuppressionType t); -// Exposed for testing. bool TemplateMatch(char *templ, const char *str); } // namespace __sanitizer Index: sanitizer_common/sanitizer_suppressions.cc =================================================================== --- sanitizer_common/sanitizer_suppressions.cc +++ sanitizer_common/sanitizer_suppressions.cc @@ -20,7 +20,7 @@ namespace __sanitizer { static const char *const kTypeStrings[SuppressionTypeCount] = { - "none", "race", "mutex", "thread", "signal", "leak" + "none", "race", "mutex", "thread", "signal", "leak", "called_from_lib" }; bool TemplateMatch(char *templ, const char *str) { @@ -129,10 +129,15 @@ } } -uptr SuppressionContext::SuppressionCount() { +uptr SuppressionContext::SuppressionCount() const { return suppressions_.size(); } +const Suppression *SuppressionContext::SuppressionAt(uptr i) const { + CHECK_LT(i, suppressions_.size()); + return &suppressions_[i]; +} + void SuppressionContext::GetMatched( InternalMmapVector *matched) { for (uptr i = 0; i < suppressions_.size(); i++) Index: sanitizer_common/tests/sanitizer_suppressions_test.cc =================================================================== --- sanitizer_common/tests/sanitizer_suppressions_test.cc +++ sanitizer_common/tests/sanitizer_suppressions_test.cc @@ -65,8 +65,10 @@ CHECK(!internal_strcmp(SuppressionTypeString(SuppressionThread), "thread")); CHECK(!internal_strcmp(SuppressionTypeString(SuppressionSignal), "signal")); CHECK(!internal_strcmp(SuppressionTypeString(SuppressionLeak), "leak")); + CHECK(!internal_strcmp(SuppressionTypeString(SuppressionLib), + "called_from_lib")); // Ensure this test is up-to-date when suppression types are added. - CHECK_EQ(SuppressionTypeCount, 6); + CHECK_EQ(SuppressionTypeCount, 7); } class SuppressionContextTest : public ::testing::Test { Index: tsan/lit_tests/ignore_lib0.cc =================================================================== --- tsan/lit_tests/ignore_lib0.cc +++ tsan/lit_tests/ignore_lib0.cc @@ -0,0 +1,30 @@ +// RUN: %clangxx_tsan -O1 %s -DLIB -fPIC -fno-sanitize=thread -shared -o %T/libignore_lib0.so +// RUN: %clangxx_tsan -O1 %s -L%T -lignore_lib0 -o %t +// RUN: echo running w/o suppressions: +// RUN: LD_LIBRARY_PATH=%T not %t 2>&1 | FileCheck %s --check-prefix=CHECK-NOSUPP +// RUN: echo running with suppressions: +// RUN: LD_LIBRARY_PATH=%T TSAN_OPTIONS="$TSAN_OPTIONS suppressions=%s.supp" %t 2>&1 | FileCheck %s --check-prefix=CHECK-WITHSUPP + +// Tests that interceptors coming from a library specified in called_from_lib +// suppression are ignored. + +#ifndef LIB + +extern "C" void libfunc(); + +int main() { + libfunc(); +} + +#else // #ifdef LIB + +#include "ignore_lib_lib.h" + +#endif // #ifdef LIB + +// CHECK-NOSUPP: WARNING: ThreadSanitizer: data race +// CHECK-NOSUPP: OK + +// CHECK-WITHSUPP-NOT: WARNING: ThreadSanitizer: data race +// CHECK-WITHSUPP: OK + Index: tsan/lit_tests/ignore_lib0.cc.supp =================================================================== --- tsan/lit_tests/ignore_lib0.cc.supp +++ tsan/lit_tests/ignore_lib0.cc.supp @@ -0,0 +1,2 @@ +called_from_lib:/libignore_lib0.so + Index: tsan/lit_tests/ignore_lib1.cc =================================================================== --- tsan/lit_tests/ignore_lib1.cc +++ tsan/lit_tests/ignore_lib1.cc @@ -0,0 +1,42 @@ +// RUN: %clangxx_tsan -O1 %s -DLIB -fPIC -fno-sanitize=thread -shared -o %T/libignore_lib1.so +// RUN: %clangxx_tsan -O1 %s -o %t +// RUN: echo running w/o suppressions: +// RUN: not %t 2>&1 | FileCheck %s --check-prefix=CHECK-NOSUPP +// RUN: echo running with suppressions: +// RUN: TSAN_OPTIONS="$TSAN_OPTIONS suppressions=%s.supp" %t 2>&1 | FileCheck %s --check-prefix=CHECK-WITHSUPP + +// Tests that interceptors coming from a dynamically loaded library specified +// in called_from_lib suppression are ignored. + +#ifndef LIB + +#include +#include +#include +#include +#include +#include + +int main(int argc, char **argv) { + std::string lib = std::string(dirname(argv[0])) + "/libignore_lib1.so"; + void *h = dlopen(lib.c_str(), RTLD_GLOBAL | RTLD_NOW); + if (h == 0) + exit(printf("failed to load the library (%d)\n", errno)); + void (*f)() = (void(*)())dlsym(h, "libfunc"); + if (f == 0) + exit(printf("failed to find the func (%d)\n", errno)); + f(); +} + +#else // #ifdef LIB + +#include "ignore_lib_lib.h" + +#endif // #ifdef LIB + +// CHECK-NOSUPP: WARNING: ThreadSanitizer: data race +// CHECK-NOSUPP: OK + +// CHECK-WITHSUPP-NOT: WARNING: ThreadSanitizer: data race +// CHECK-WITHSUPP: OK + Index: tsan/lit_tests/ignore_lib1.cc.supp =================================================================== --- tsan/lit_tests/ignore_lib1.cc.supp +++ tsan/lit_tests/ignore_lib1.cc.supp @@ -0,0 +1,2 @@ +called_from_lib:/libignore_lib1.so$ + Index: tsan/lit_tests/ignore_lib2.cc =================================================================== --- tsan/lit_tests/ignore_lib2.cc +++ tsan/lit_tests/ignore_lib2.cc @@ -0,0 +1,33 @@ +// RUN: %clangxx_tsan -O1 %s -DLIB -fPIC -fno-sanitize=thread -shared -o %T/libignore_lib2_0.so +// RUN: %clangxx_tsan -O1 %s -DLIB -fPIC -fno-sanitize=thread -shared -o %T/libignore_lib2_1.so +// RUN: %clangxx_tsan -O1 %s -o %t +// RUN: TSAN_OPTIONS="$TSAN_OPTIONS suppressions=%s.supp" not %t 2>&1 | FileCheck %s + +// Tests that called_from_lib suppression matched against 2 libraries +// causes program crash (this is not supported). + +#ifndef LIB + +#include +#include +#include +#include + +int main(int argc, char **argv) { + std::string lib0 = std::string(dirname(argv[0])) + "/libignore_lib2_0.so"; + std::string lib1 = std::string(dirname(argv[0])) + "/libignore_lib2_1.so"; + dlopen(lib0.c_str(), RTLD_GLOBAL | RTLD_NOW); + dlopen(lib1.c_str(), RTLD_GLOBAL | RTLD_NOW); + fprintf(stderr, "OK\n"); +} + +#else // #ifdef LIB + +extern "C" void libfunc() { +} + +#endif // #ifdef LIB + +// CHECK: ThreadSanitizer: called_from_lib suppression 'ignore_lib2' is matched against 2 libraries +// CHECK-NOT: OK + Index: tsan/lit_tests/ignore_lib2.cc.supp =================================================================== --- tsan/lit_tests/ignore_lib2.cc.supp +++ tsan/lit_tests/ignore_lib2.cc.supp @@ -0,0 +1,2 @@ +called_from_lib:ignore_lib2 + Index: tsan/lit_tests/ignore_lib3.cc =================================================================== --- tsan/lit_tests/ignore_lib3.cc +++ tsan/lit_tests/ignore_lib3.cc @@ -0,0 +1,33 @@ +// RUN: %clangxx_tsan -O1 %s -DLIB -fPIC -fno-sanitize=thread -shared -o %T/libignore_lib3.so +// RUN: %clangxx_tsan -O1 %s -o %t +// RUN: TSAN_OPTIONS="$TSAN_OPTIONS suppressions=%s.supp" not %t 2>&1 | FileCheck %s + +// Tests that unloading of a library matched against called_from_lib suppression +// causes program crash (this is not supported). + +#ifndef LIB + +#include +#include +#include +#include +#include +#include + +int main(int argc, char **argv) { + std::string lib = std::string(dirname(argv[0])) + "/libignore_lib3.so"; + void *h = dlopen(lib.c_str(), RTLD_GLOBAL | RTLD_NOW); + dlclose(h); + fprintf(stderr, "OK\n"); +} + +#else // #ifdef LIB + +extern "C" void libfunc() { +} + +#endif // #ifdef LIB + +// CHECK: ThreadSanitizer: library {{.*}} that was matched against called_from_lib suppression 'ignore_lib3.so' is unloaded +// CHECK-NOT: OK + Index: tsan/lit_tests/ignore_lib3.cc.supp =================================================================== --- tsan/lit_tests/ignore_lib3.cc.supp +++ tsan/lit_tests/ignore_lib3.cc.supp @@ -0,0 +1,2 @@ +called_from_lib:ignore_lib3.so + Index: tsan/lit_tests/ignore_lib_lib.h =================================================================== --- tsan/lit_tests/ignore_lib_lib.h +++ tsan/lit_tests/ignore_lib_lib.h @@ -0,0 +1,25 @@ +#include +#include +#include +#include +#include + +void *volatile mem; +volatile int len; + +void *Thread(void *p) { + while ((p = __atomic_load_n(&mem, __ATOMIC_ACQUIRE)) == 0) + usleep(100); + memset(p, 0, len); + return 0; +} + +extern "C" void libfunc() { + pthread_t t; + pthread_create(&t, 0, Thread, 0); + len = 10; + __atomic_store_n(&mem, malloc(len), __ATOMIC_RELEASE); + pthread_join(t, 0); + free(mem); + fprintf(stderr, "OK\n"); +} Index: tsan/lit_tests/java_alloc.cc =================================================================== --- tsan/lit_tests/java_alloc.cc +++ tsan/lit_tests/java_alloc.cc @@ -20,7 +20,6 @@ int main() { jptr jheap = (jptr)malloc(kHeapSize); - __tsan_java_preinit("[vdso]"); __tsan_java_init(jheap, kHeapSize); pthread_t th; pthread_create(&th, 0, Thread, (void*)(jheap + kHeapSize / 4)); Index: tsan/lit_tests/java_lock.cc =================================================================== --- tsan/lit_tests/java_lock.cc +++ tsan/lit_tests/java_lock.cc @@ -16,7 +16,6 @@ int main() { int const kHeapSize = 1024 * 1024; void *jheap = malloc(kHeapSize); - __tsan_java_preinit(0); __tsan_java_init((jptr)jheap, kHeapSize); const int kBlockSize = 16; __tsan_java_alloc((jptr)jheap, kBlockSize); Index: tsan/rtl/tsan_interceptors.cc =================================================================== --- tsan/rtl/tsan_interceptors.cc +++ tsan/rtl/tsan_interceptors.cc @@ -22,6 +22,7 @@ #include "interception/interception.h" #include "tsan_interface.h" #include "tsan_platform.h" +#include "tsan_suppressions.h" #include "tsan_rtl.h" #include "tsan_mman.h" #include "tsan_fd.h" @@ -126,18 +127,16 @@ SignalDesc pending_signals[kSigCount]; }; -// Used to ignore interceptors coming directly from libjvm.so. -atomic_uintptr_t libjvm_begin; -atomic_uintptr_t libjvm_end; - -static bool libjvm_check(uptr pc) { - uptr begin = atomic_load(&libjvm_begin, memory_order_relaxed); - if (begin != 0 && pc >= begin) { - uptr end = atomic_load(&libjvm_end, memory_order_relaxed); - if (end != 0 && pc < end) - return true; - } - return false; +// 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)]; +static LibIgnore *libignore() { + return reinterpret_cast(&libignore_placeholder[0]); +} + +void InitializeLibIgnore() { + libignore()->Init(*GetSuppressionContext()); + libignore()->OnLibraryLoaded(); } } // namespace __tsan @@ -162,12 +161,14 @@ private: ThreadState *const thr_; const int in_rtl_; + bool in_ignored_lib_; }; ScopedInterceptor::ScopedInterceptor(ThreadState *thr, const char *fname, uptr pc) : thr_(thr) - , in_rtl_(thr->in_rtl) { + , in_rtl_(thr->in_rtl) + , in_ignored_lib_(false) { if (thr_->in_rtl == 0) { Initialize(thr); FuncEntry(thr, pc); @@ -176,9 +177,18 @@ } else { thr_->in_rtl++; } + if (!thr_->in_ignored_lib && libignore()->IsIgnored(pc)) { + in_ignored_lib_ = true; + thr_->in_ignored_lib = true; + ThreadIgnoreBegin(thr_); + } } ScopedInterceptor::~ScopedInterceptor() { + if (in_ignored_lib_) { + thr_->in_ignored_lib = false; + ThreadIgnoreEnd(thr_); + } thr_->in_rtl--; if (thr_->in_rtl == 0) { FuncExit(thr_); @@ -203,7 +213,7 @@ Printf("FATAL: ThreadSanitizer: failed to intercept %s\n", #func); \ Die(); \ } \ - if (thr->in_rtl > 1 || libjvm_check(pc)) \ + if (thr->in_rtl > 1 || thr->in_ignored_lib) \ return REAL(func)(__VA_ARGS__); \ /**/ @@ -246,6 +256,28 @@ return res; } +TSAN_INTERCEPTOR(void*, dlopen, const char *filename, int flag) { + SCOPED_INTERCEPTOR_RAW(dlopen, filename, flag); + // dlopen will execute global constructors, so it must be not in rtl. + CHECK_EQ(thr->in_rtl, 1); + thr->in_rtl = 0; + void *res = REAL(dlopen)(filename, flag); + thr->in_rtl = 1; + libignore()->OnLibraryLoaded(); + return res; +} + +TSAN_INTERCEPTOR(int, dlclose, void *handle) { + SCOPED_INTERCEPTOR_RAW(dlclose, handle); + // dlclose will execute global destructors, so it must be not in rtl. + CHECK_EQ(thr->in_rtl, 1); + thr->in_rtl = 0; + int res = REAL(dlclose)(handle); + thr->in_rtl = 1; + libignore()->OnLibraryUnloaded(); + return res; +} + class AtExitContext { public: AtExitContext() @@ -441,7 +473,7 @@ } TSAN_INTERCEPTOR(void*, malloc, uptr size) { - if (cur_thread()->in_symbolizer || libjvm_check(GET_CALLER_PC())) + if (cur_thread()->in_symbolizer) return __libc_malloc(size); void *p = 0; { @@ -458,7 +490,7 @@ } TSAN_INTERCEPTOR(void*, calloc, uptr size, uptr n) { - if (cur_thread()->in_symbolizer || libjvm_check(GET_CALLER_PC())) + if (cur_thread()->in_symbolizer) return __libc_calloc(size, n); if (__sanitizer::CallocShouldReturnNullDueToOverflow(size, n)) return AllocatorReturnNull(); @@ -474,7 +506,7 @@ } TSAN_INTERCEPTOR(void*, realloc, void *p, uptr size) { - if (cur_thread()->in_symbolizer || libjvm_check(GET_CALLER_PC())) + if (cur_thread()->in_symbolizer) return __libc_realloc(p, size); if (p) invoke_free_hook(p); @@ -489,7 +521,7 @@ TSAN_INTERCEPTOR(void, free, void *p) { if (p == 0) return; - if (cur_thread()->in_symbolizer || libjvm_check(GET_CALLER_PC())) + if (cur_thread()->in_symbolizer) return __libc_free(p); invoke_free_hook(p); SCOPED_INTERCEPTOR_RAW(free, p); @@ -499,7 +531,7 @@ TSAN_INTERCEPTOR(void, cfree, void *p) { if (p == 0) return; - if (cur_thread()->in_symbolizer || libjvm_check(GET_CALLER_PC())) + if (cur_thread()->in_symbolizer) return __libc_free(p); invoke_free_hook(p); SCOPED_INTERCEPTOR_RAW(cfree, p); @@ -508,13 +540,11 @@ TSAN_INTERCEPTOR(uptr, malloc_usable_size, void *p) { SCOPED_INTERCEPTOR_RAW(malloc_usable_size, p); - if (libjvm_check(pc)) - return malloc_usable_size(p); return user_alloc_usable_size(thr, pc, p); } #define OPERATOR_NEW_BODY(mangled_name) \ - if (cur_thread()->in_symbolizer || libjvm_check(GET_CALLER_PC())) \ + if (cur_thread()->in_symbolizer) \ return __libc_malloc(size); \ void *p = 0; \ { \ @@ -550,7 +580,7 @@ #define OPERATOR_DELETE_BODY(mangled_name) \ if (ptr == 0) return; \ - if (cur_thread()->in_symbolizer || libjvm_check(GET_CALLER_PC())) \ + if (cur_thread()->in_symbolizer) \ return __libc_free(ptr); \ invoke_free_hook(ptr); \ SCOPED_INTERCEPTOR_RAW(mangled_name, ptr); \ @@ -684,15 +714,6 @@ TSAN_INTERCEPTOR(char*, strdup, const char *str) { SCOPED_TSAN_INTERCEPTOR(strdup, str); - if (libjvm_check(pc)) { - // The memory must come from libc malloc, - // and we must not instrument accesses in this case. - uptr n = internal_strlen(str) + 1; - void *p = __libc_malloc(n); - if (p == 0) - return 0; - return (char*)internal_memcpy(p, str, n); - } // strdup will call malloc, so no instrumentation is required here. return REAL(strdup)(str); } @@ -747,23 +768,23 @@ } TSAN_INTERCEPTOR(void*, memalign, uptr align, uptr sz) { - SCOPED_TSAN_INTERCEPTOR(memalign, align, sz); + SCOPED_INTERCEPTOR_RAW(memalign, align, sz); return user_alloc(thr, pc, sz, align); } TSAN_INTERCEPTOR(void*, valloc, uptr sz) { - SCOPED_TSAN_INTERCEPTOR(valloc, sz); + SCOPED_INTERCEPTOR_RAW(valloc, sz); return user_alloc(thr, pc, sz, GetPageSizeCached()); } TSAN_INTERCEPTOR(void*, pvalloc, uptr sz) { - SCOPED_TSAN_INTERCEPTOR(pvalloc, sz); + SCOPED_INTERCEPTOR_RAW(pvalloc, sz); sz = RoundUp(sz, GetPageSizeCached()); return user_alloc(thr, pc, sz, GetPageSizeCached()); } TSAN_INTERCEPTOR(int, posix_memalign, void **memptr, uptr align, uptr sz) { - SCOPED_TSAN_INTERCEPTOR(posix_memalign, memptr, align, sz); + SCOPED_INTERCEPTOR_RAW(posix_memalign, memptr, align, sz); *memptr = user_alloc(thr, pc, sz, align); return 0; } @@ -852,7 +873,7 @@ TSAN_INTERCEPTOR(int, pthread_create, void *th, void *attr, void *(*callback)(void*), void * param) { - SCOPED_TSAN_INTERCEPTOR(pthread_create, th, attr, callback, param); + SCOPED_INTERCEPTOR_RAW(pthread_create, th, attr, callback, param); __sanitizer_pthread_attr_t myattr; if (attr == 0) { pthread_attr_init(&myattr); @@ -886,7 +907,7 @@ } TSAN_INTERCEPTOR(int, pthread_join, void *th, void **ret) { - SCOPED_TSAN_INTERCEPTOR(pthread_join, th, ret); + SCOPED_INTERCEPTOR_RAW(pthread_join, th, ret); int tid = ThreadTid(thr, pc, (uptr)th); int res = BLOCK_REAL(pthread_join)(th, ret); if (res == 0) { @@ -1820,7 +1841,7 @@ } TSAN_INTERCEPTOR(int, fork, int fake) { - SCOPED_TSAN_INTERCEPTOR(fork, fake); + SCOPED_INTERCEPTOR_RAW(fork, fake); int pid = REAL(fork)(fake); if (pid == 0) { // child @@ -2174,6 +2195,8 @@ TSAN_INTERCEPT(munlockall); TSAN_INTERCEPT(fork); + TSAN_INTERCEPT(dlopen); + TSAN_INTERCEPT(dlclose); TSAN_INTERCEPT(on_exit); TSAN_INTERCEPT(__cxa_atexit); Index: tsan/rtl/tsan_interface_java.h =================================================================== --- tsan/rtl/tsan_interface_java.h +++ tsan/rtl/tsan_interface_java.h @@ -34,11 +34,7 @@ typedef unsigned long jptr; // NOLINT -// Must be called before any other callback from Java, right after dlopen -// of JVM shared lib. If libjvm_path is specified, then all interceptors -// coming directly from JVM will be ignored. -void __tsan_java_preinit(const char *libjvm_path) INTERFACE_ATTRIBUTE; -// Must be called after __tsan_java_preinit but before any other callback. +// Must be called before any other callback from Java. void __tsan_java_init(jptr heap_begin, jptr heap_size) INTERFACE_ATTRIBUTE; // Must be called when the application exits. // Not necessary the last callback (concurrently running threads are OK). Index: tsan/rtl/tsan_interface_java.cc =================================================================== --- tsan/rtl/tsan_interface_java.cc +++ tsan/rtl/tsan_interface_java.cc @@ -96,8 +96,6 @@ static u64 jctx_buf[sizeof(JavaContext) / sizeof(u64) + 1]; static JavaContext *jctx; -extern atomic_uintptr_t libjvm_begin; -extern atomic_uintptr_t libjvm_end; static BlockDesc *getblock(uptr addr) { uptr i = (addr - jctx->heap_begin) / kHeapAlignment; @@ -166,17 +164,6 @@ ScopedJavaFunc scoped(thr, caller_pc); \ /**/ -void __tsan_java_preinit(const char *libjvm_path) { - SCOPED_JAVA_FUNC(__tsan_java_preinit); - if (libjvm_path) { - uptr begin, end; - if (GetCodeRangeForFile(libjvm_path, &begin, &end)) { - atomic_store(&libjvm_begin, begin, memory_order_relaxed); - atomic_store(&libjvm_end, end, memory_order_relaxed); - } - } -} - void __tsan_java_init(jptr heap_begin, jptr heap_size) { SCOPED_JAVA_FUNC(__tsan_java_init); DPrintf("#%d: java_init(%p, %p)\n", thr->tid, heap_begin, heap_size); Index: tsan/rtl/tsan_rtl.h =================================================================== --- tsan/rtl/tsan_rtl.h +++ tsan/rtl/tsan_rtl.h @@ -29,6 +29,7 @@ #include "sanitizer_common/sanitizer_allocator.h" #include "sanitizer_common/sanitizer_allocator_internal.h" #include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_libignore.h" #include "sanitizer_common/sanitizer_suppressions.h" #include "sanitizer_common/sanitizer_thread_registry.h" #include "tsan_clock.h" @@ -434,6 +435,7 @@ const int unique_id; int in_rtl; bool in_symbolizer; + bool in_ignored_lib; bool is_alive; bool is_freeing; bool is_vptr_access; @@ -598,6 +600,7 @@ void DontNeedShadowFor(uptr addr, uptr size); void InitializeShadowMemory(); void InitializeInterceptors(); +void InitializeLibIgnore(); void InitializeDynamicAnnotations(); void ReportRace(ThreadState *thr); Index: tsan/rtl/tsan_rtl.cc =================================================================== --- tsan/rtl/tsan_rtl.cc +++ tsan/rtl/tsan_rtl.cc @@ -214,6 +214,7 @@ __sanitizer_set_report_path(flags()->log_path); InitializeSuppressions(); #ifndef TSAN_GO + InitializeLibIgnore(); // Initialize external symbolizer before internal threads are started. const char *external_symbolizer = flags()->external_symbolizer_path; if (external_symbolizer != 0 && external_symbolizer[0] != '\0') { Index: tsan/rtl/tsan_stat.h =================================================================== --- tsan/rtl/tsan_stat.h +++ tsan/rtl/tsan_stat.h @@ -366,6 +366,8 @@ StatInt_sigprocmask, StatInt_backtrace, StatInt_backtrace_symbols, + StatInt_dlopen, + StatInt_dlclose, // Dynamic annotations. StatAnnotation, Index: tsan/rtl/tsan_stat.cc =================================================================== --- tsan/rtl/tsan_stat.cc +++ tsan/rtl/tsan_stat.cc @@ -371,6 +371,8 @@ name[StatInt_sigprocmask] = " sigprocmask "; name[StatInt_backtrace] = " backtrace "; name[StatInt_backtrace_symbols] = " backtrace_symbols "; + name[StatInt_dlopen] = " dlopen "; + name[StatInt_dlclose] = " dlclose "; name[StatAnnotation] = "Dynamic annotations "; name[StatAnnotateHappensBefore] = " HappensBefore "; Index: tsan/rtl/tsan_suppressions.h =================================================================== --- tsan/rtl/tsan_suppressions.h +++ tsan/rtl/tsan_suppressions.h @@ -22,6 +22,7 @@ void PrintMatchedSuppressions(); uptr IsSuppressed(ReportType typ, const ReportStack *stack, Suppression **sp); uptr IsSuppressed(ReportType typ, const ReportLocation *loc, Suppression **sp); +SuppressionContext *GetSuppressionContext(); } // namespace __tsan Index: tsan/rtl/tsan_suppressions.cc =================================================================== --- tsan/rtl/tsan_suppressions.cc +++ tsan/rtl/tsan_suppressions.cc @@ -87,6 +87,11 @@ #endif } +SuppressionContext *GetSuppressionContext() { + CHECK_NE(g_ctx, 0); + return g_ctx; +} + SuppressionType conv(ReportType typ) { if (typ == ReportTypeRace) return SuppressionRace;