diff options
Diffstat (limited to 'lib/tsan')
-rw-r--r-- | lib/tsan/CMakeLists.txt | 55 | ||||
-rw-r--r-- | lib/tsan/Makefile.mk | 18 | ||||
-rw-r--r-- | lib/tsan/dd/dd_rtl.cc | 8 | ||||
-rw-r--r-- | lib/tsan/go/build.bat | 4 | ||||
-rwxr-xr-x | lib/tsan/go/buildgo.sh | 2 | ||||
-rw-r--r-- | lib/tsan/rtl/Makefile.mk | 25 | ||||
-rw-r--r-- | lib/tsan/rtl/tsan_defs.h | 21 | ||||
-rw-r--r-- | lib/tsan/rtl/tsan_flags.cc | 2 | ||||
-rw-r--r-- | lib/tsan/rtl/tsan_flags.inc | 3 | ||||
-rw-r--r-- | lib/tsan/rtl/tsan_interceptors.cc | 39 | ||||
-rw-r--r-- | lib/tsan/rtl/tsan_interface_atomic.cc | 7 | ||||
-rw-r--r-- | lib/tsan/rtl/tsan_platform.h | 48 | ||||
-rw-r--r-- | lib/tsan/rtl/tsan_platform_linux.cc | 21 | ||||
-rw-r--r-- | lib/tsan/rtl/tsan_report.cc | 5 | ||||
-rw-r--r-- | lib/tsan/rtl/tsan_rtl.cc | 39 | ||||
-rw-r--r-- | lib/tsan/rtl/tsan_rtl.h | 40 | ||||
-rw-r--r-- | lib/tsan/rtl/tsan_rtl_report.cc | 6 | ||||
-rw-r--r-- | lib/tsan/rtl/tsan_rtl_thread.cc | 4 | ||||
-rw-r--r-- | lib/tsan/rtl/tsan_stat.cc | 9 | ||||
-rw-r--r-- | lib/tsan/rtl/tsan_suppressions.cc | 81 | ||||
-rw-r--r-- | lib/tsan/rtl/tsan_suppressions.h | 9 | ||||
-rw-r--r-- | lib/tsan/rtl/tsan_trace.h | 8 | ||||
-rw-r--r-- | lib/tsan/tests/CMakeLists.txt | 40 |
23 files changed, 301 insertions, 193 deletions
diff --git a/lib/tsan/CMakeLists.txt b/lib/tsan/CMakeLists.txt index baf07a034e3b..9f6d63041a68 100644 --- a/lib/tsan/CMakeLists.txt +++ b/lib/tsan/CMakeLists.txt @@ -79,35 +79,40 @@ set(TSAN_HEADERS set(TSAN_RUNTIME_LIBRARIES) add_custom_target(tsan) # TSan is currently supported on 64-bit Linux only. -if(CAN_TARGET_x86_64 AND UNIX AND NOT APPLE) - set(TSAN_ASM_SOURCES rtl/tsan_rtl_amd64.S) - # Pass ASM file directly to the C++ compiler. - set_source_files_properties(${TSAN_ASM_SOURCES} PROPERTIES - LANGUAGE C) - set(arch "x86_64") - add_compiler_rt_runtime(clang_rt.tsan-${arch} ${arch} STATIC - SOURCES ${TSAN_SOURCES} ${TSAN_ASM_SOURCES} - $<TARGET_OBJECTS:RTInterception.${arch}> - $<TARGET_OBJECTS:RTSanitizerCommon.${arch}> - $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}> - CFLAGS ${TSAN_RTL_CFLAGS} - DEFS ${TSAN_COMMON_DEFINITIONS}) - list(APPEND TSAN_RUNTIME_LIBRARIES clang_rt.tsan-${arch}) - add_sanitizer_rt_symbols(clang_rt.tsan-${arch} rtl/tsan.syms.extra) - add_dependencies(tsan clang_rt.tsan-${arch} - clang_rt.tsan-${arch}-symbols) +if(UNIX AND NOT APPLE) + foreach(arch ${TSAN_SUPPORTED_ARCH}) + if(arch STREQUAL "x86_64") + set(TSAN_ASM_SOURCES rtl/tsan_rtl_amd64.S) + # Pass ASM file directly to the C++ compiler. + set_source_files_properties(${TSAN_ASM_SOURCES} PROPERTIES + LANGUAGE C) + # Sanity check for Go runtime. + set(BUILDGO_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/go/buildgo.sh) + add_custom_target(GotsanRuntimeCheck + COMMAND CC=${CMAKE_C_COMPILER} IN_TMPDIR=1 SILENT=1 ${BUILDGO_SCRIPT} + DEPENDS clang_rt.tsan-${arch} ${BUILDGO_SCRIPT} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/go + COMMENT "Checking TSan Go runtime..." + VERBATIM) + else() + set(TSAN_ASM_SOURCES) + endif() + add_compiler_rt_runtime(clang_rt.tsan-${arch} ${arch} STATIC + SOURCES ${TSAN_SOURCES} ${TSAN_ASM_SOURCES} + $<TARGET_OBJECTS:RTInterception.${arch}> + $<TARGET_OBJECTS:RTSanitizerCommon.${arch}> + $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}> + CFLAGS ${TSAN_RTL_CFLAGS} + DEFS ${TSAN_COMMON_DEFINITIONS}) + list(APPEND TSAN_RUNTIME_LIBRARIES clang_rt.tsan-${arch}) + add_sanitizer_rt_symbols(clang_rt.tsan-${arch} rtl/tsan.syms.extra) + add_dependencies(tsan clang_rt.tsan-${arch} + clang_rt.tsan-${arch}-symbols) + endforeach() endif() add_dependencies(compiler-rt tsan) -# Sanity check for Go runtime. -set(BUILDGO_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/go/buildgo.sh) -add_custom_target(GotsanRuntimeCheck - COMMAND CC=${CMAKE_C_COMPILER} IN_TMPDIR=1 SILENT=1 ${BUILDGO_SCRIPT} - DEPENDS clang_rt.tsan-${arch} ${BUILDGO_SCRIPT} - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/go - COMMENT "Checking TSan Go runtime..." - VERBATIM) # Build libcxx instrumented with TSan. if(TSAN_SUPPORTED_ARCH AND diff --git a/lib/tsan/Makefile.mk b/lib/tsan/Makefile.mk deleted file mode 100644 index 70fb610bdc61..000000000000 --- a/lib/tsan/Makefile.mk +++ /dev/null @@ -1,18 +0,0 @@ -#===- lib/tsan/Makefile.mk ---------------------------------*- Makefile -*--===# -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -#===------------------------------------------------------------------------===# - -ModuleName := tsan -SubDirs := rtl -Sources := -ObjNames := -Dependencies := - -Implementation := Generic - -TsanFunctions := diff --git a/lib/tsan/dd/dd_rtl.cc b/lib/tsan/dd/dd_rtl.cc index 2ba1ee324111..99b8ee597cd1 100644 --- a/lib/tsan/dd/dd_rtl.cc +++ b/lib/tsan/dd/dd_rtl.cc @@ -65,8 +65,8 @@ u32 Callback::Unwind() { return CurrentStackTrace(thr, 3); } -void InitializeFlags(Flags *f, const char *env) { - internal_memset(f, 0, sizeof(*f)); +static void InitializeFlags() { + Flags *f = flags(); // Default values. f->second_deadlock_stack = false; @@ -84,7 +84,7 @@ void InitializeFlags(Flags *f, const char *env) { FlagParser parser; RegisterFlag(&parser, "second_deadlock_stack", "", &f->second_deadlock_stack); RegisterCommonFlags(&parser); - parser.ParseString(env); + parser.ParseString(GetEnv("DSAN_OPTIONS")); SetVerbosity(common_flags()->verbosity); } @@ -93,7 +93,7 @@ void Initialize() { ctx = new(ctx_mem) Context(); InitializeInterceptors(); - InitializeFlags(flags(), GetEnv("DSAN_OPTIONS")); + InitializeFlags(); ctx->dd = DDetector::Create(flags()); } diff --git a/lib/tsan/go/build.bat b/lib/tsan/go/build.bat index 9b350a2d633e..7d393dc0e025 100644 --- a/lib/tsan/go/build.bat +++ b/lib/tsan/go/build.bat @@ -1,4 +1,4 @@ -type tsan_go.cc ..\rtl\tsan_interface_atomic.cc ..\rtl\tsan_clock.cc ..\rtl\tsan_flags.cc ..\rtl\tsan_md5.cc ..\rtl\tsan_mutex.cc ..\rtl\tsan_report.cc ..\rtl\tsan_rtl.cc ..\rtl\tsan_rtl_mutex.cc ..\rtl\tsan_rtl_report.cc ..\rtl\tsan_rtl_thread.cc ..\rtl\tsan_stat.cc ..\rtl\tsan_suppressions.cc ..\rtl\tsan_sync.cc ..\rtl\tsan_stack_trace.cc ..\..\sanitizer_common\sanitizer_allocator.cc ..\..\sanitizer_common\sanitizer_common.cc ..\..\sanitizer_common\sanitizer_flags.cc ..\..\sanitizer_common\sanitizer_stacktrace.cc ..\..\sanitizer_common\sanitizer_libc.cc ..\..\sanitizer_common\sanitizer_printf.cc ..\..\sanitizer_common\sanitizer_suppressions.cc ..\..\sanitizer_common\sanitizer_thread_registry.cc ..\rtl\tsan_platform_windows.cc ..\..\sanitizer_common\sanitizer_win.cc ..\..\sanitizer_common\sanitizer_deadlock_detector1.cc ..\..\sanitizer_common\sanitizer_stackdepot.cc ..\..\sanitizer_common\sanitizer_persistent_allocator.cc > gotsan.cc +type tsan_go.cc ..\rtl\tsan_interface_atomic.cc ..\rtl\tsan_clock.cc ..\rtl\tsan_flags.cc ..\rtl\tsan_md5.cc ..\rtl\tsan_mutex.cc ..\rtl\tsan_report.cc ..\rtl\tsan_rtl.cc ..\rtl\tsan_rtl_mutex.cc ..\rtl\tsan_rtl_report.cc ..\rtl\tsan_rtl_thread.cc ..\rtl\tsan_stat.cc ..\rtl\tsan_suppressions.cc ..\rtl\tsan_sync.cc ..\rtl\tsan_stack_trace.cc ..\..\sanitizer_common\sanitizer_allocator.cc ..\..\sanitizer_common\sanitizer_common.cc ..\..\sanitizer_common\sanitizer_flags.cc ..\..\sanitizer_common\sanitizer_stacktrace.cc ..\..\sanitizer_common\sanitizer_libc.cc ..\..\sanitizer_common\sanitizer_printf.cc ..\..\sanitizer_common\sanitizer_suppressions.cc ..\..\sanitizer_common\sanitizer_thread_registry.cc ..\rtl\tsan_platform_windows.cc ..\..\sanitizer_common\sanitizer_win.cc ..\..\sanitizer_common\sanitizer_deadlock_detector1.cc ..\..\sanitizer_common\sanitizer_stackdepot.cc ..\..\sanitizer_common\sanitizer_persistent_allocator.cc ..\..\sanitizer_common\sanitizer_flag_parser.cc ..\..\sanitizer_common\sanitizer_symbolizer.cc > gotsan.cc -gcc -c -o race_windows_amd64.syso gotsan.cc -I..\rtl -I..\.. -I..\..\sanitizer_common -I..\..\..\include -m64 -Wall -fno-exceptions -fno-rtti -DSANITIZER_GO -Wno-error=attributes -Wno-attributes -Wno-format -DSANITIZER_DEBUG=0 -O3 -fomit-frame-pointer +gcc -c -o race_windows_amd64.syso gotsan.cc -I..\rtl -I..\.. -I..\..\sanitizer_common -I..\..\..\include -m64 -Wall -fno-exceptions -fno-rtti -DSANITIZER_GO -Wno-error=attributes -Wno-attributes -Wno-format -Wno-maybe-uninitialized -DSANITIZER_DEBUG=0 -O3 -fomit-frame-pointer -std=c++11 diff --git a/lib/tsan/go/buildgo.sh b/lib/tsan/go/buildgo.sh index e00408cb10f0..5ac60349e081 100755 --- a/lib/tsan/go/buildgo.sh +++ b/lib/tsan/go/buildgo.sh @@ -45,7 +45,6 @@ if [ "`uname -a | grep Linux`" != "" ]; then ../../sanitizer_common/sanitizer_procmaps_common.cc ../../sanitizer_common/sanitizer_procmaps_linux.cc ../../sanitizer_common/sanitizer_linux.cc - ../../sanitizer_common/sanitizer_linux_libcdep.cc ../../sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc " elif [ "`uname -a | grep FreeBSD`" != "" ]; then @@ -60,7 +59,6 @@ elif [ "`uname -a | grep FreeBSD`" != "" ]; then ../../sanitizer_common/sanitizer_procmaps_common.cc ../../sanitizer_common/sanitizer_procmaps_freebsd.cc ../../sanitizer_common/sanitizer_linux.cc - ../../sanitizer_common/sanitizer_linux_libcdep.cc ../../sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc " elif [ "`uname -a | grep Darwin`" != "" ]; then diff --git a/lib/tsan/rtl/Makefile.mk b/lib/tsan/rtl/Makefile.mk deleted file mode 100644 index 2687123f731d..000000000000 --- a/lib/tsan/rtl/Makefile.mk +++ /dev/null @@ -1,25 +0,0 @@ -#===- lib/tsan/rtl/Makefile.mk -----------------------------*- Makefile -*--===# -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -#===------------------------------------------------------------------------===# - -ModuleName := tsan -SubDirs := - -Sources := $(foreach file,$(wildcard $(Dir)/*.cc),$(notdir $(file))) -AsmSources := $(foreach file,$(wildcard $(Dir)/*.S),$(notdir $(file))) -ObjNames := $(Sources:%.cc=%.o) $(AsmSources:%.S=%.o) - -Implementation := Generic - -# FIXME: use automatic dependencies? -Dependencies := $(wildcard $(Dir)/*.h) -Dependencies += $(wildcard $(Dir)/../../interception/*.h) -Dependencies += $(wildcard $(Dir)/../../sanitizer_common/*.h) - -# Define a convenience variable for all the tsan functions. -TsanFunctions += $(Sources:%.cc=%) $(AsmSources:%.S=%) diff --git a/lib/tsan/rtl/tsan_defs.h b/lib/tsan/rtl/tsan_defs.h index f19aee999332..910a483127d5 100644 --- a/lib/tsan/rtl/tsan_defs.h +++ b/lib/tsan/rtl/tsan_defs.h @@ -18,6 +18,15 @@ #include "sanitizer_common/sanitizer_libc.h" #include "tsan_stat.h" +// Setup defaults for compile definitions. +#ifndef TSAN_NO_HISTORY +# define TSAN_NO_HISTORY 0 +#endif + +#ifndef TSAN_COLLECT_STATS +# define TSAN_COLLECT_STATS 0 +#endif + namespace __tsan { #ifdef SANITIZER_GO @@ -35,7 +44,11 @@ const char *const kTsanOptionsEnv = "TSAN_OPTIONS"; const int kTidBits = 13; const unsigned kMaxTid = 1 << kTidBits; +#ifndef SANITIZER_GO const unsigned kMaxTidInClock = kMaxTid * 2; // This includes msb 'freed' bit. +#else +const unsigned kMaxTidInClock = kMaxTid; // Go does not track freed memory. +#endif const int kClkBits = 42; const unsigned kMaxTidReuse = (1 << (64 - kClkBits)) - 1; const uptr kShadowStackSize = 64 * 1024; @@ -59,18 +72,12 @@ const uptr kMetaShadowCell = 8; // Size of a single meta shadow value (u32). const uptr kMetaShadowSize = 4; -#if defined(TSAN_NO_HISTORY) && TSAN_NO_HISTORY +#if TSAN_NO_HISTORY const bool kCollectHistory = false; #else const bool kCollectHistory = true; #endif -#if defined(TSAN_COLLECT_STATS) && TSAN_COLLECT_STATS -const bool kCollectStats = true; -#else -const bool kCollectStats = false; -#endif - // The following "build consistency" machinery ensures that all source files // are built in the same configuration. Inconsistent builds lead to // hard to debug crashes. diff --git a/lib/tsan/rtl/tsan_flags.cc b/lib/tsan/rtl/tsan_flags.cc index fed3de8db2ed..1e81ef3d0003 100644 --- a/lib/tsan/rtl/tsan_flags.cc +++ b/lib/tsan/rtl/tsan_flags.cc @@ -62,7 +62,9 @@ void InitializeFlags(Flags *f, const char *env) { CommonFlags cf; cf.CopyFrom(*common_flags()); cf.allow_addr2line = true; +#ifndef SANITIZER_GO cf.detect_deadlocks = true; +#endif cf.print_suppressions = false; cf.stack_trace_format = " #%n %f %S %M"; OverrideCommonFlags(cf); diff --git a/lib/tsan/rtl/tsan_flags.inc b/lib/tsan/rtl/tsan_flags.inc index 2925f38482a2..e4994685fa0d 100644 --- a/lib/tsan/rtl/tsan_flags.inc +++ b/lib/tsan/rtl/tsan_flags.inc @@ -63,7 +63,7 @@ TSAN_FLAG(bool, stop_on_start, false, TSAN_FLAG(bool, running_on_valgrind, false, "Controls whether RunningOnValgrind() returns true or false.") TSAN_FLAG( - int, history_size, kGoMode ? 1 : 2, // There are a lot of goroutines in Go. + int, history_size, kGoMode ? 1 : 3, // There are a lot of goroutines in Go. "Per-thread history size, controls how many previous memory accesses " "are remembered per thread. Possible values are [0..7]. " "history_size=0 amounts to 32K memory accesses. Each next value doubles " @@ -76,3 +76,4 @@ TSAN_FLAG(int, io_sync, 1, "2 - global synchronization of all IO operations.") TSAN_FLAG(bool, die_after_fork, true, "Die after multi-threaded fork if the child creates new threads.") +TSAN_FLAG(const char *, suppressions, "", "Suppressions file name.") diff --git a/lib/tsan/rtl/tsan_interceptors.cc b/lib/tsan/rtl/tsan_interceptors.cc index 9a6401167bc1..31ff7d56aac7 100644 --- a/lib/tsan/rtl/tsan_interceptors.cc +++ b/lib/tsan/rtl/tsan_interceptors.cc @@ -39,17 +39,27 @@ using namespace __tsan; // NOLINT #define stderr __stderrp #endif +#ifdef __mips__ +const int kSigCount = 129; +#else 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]; +}; +#else struct ucontext_t { // The size is determined by looking at sizeof of real ucontext_t on linux. u64 opaque[936 / sizeof(u64) + 1]; }; +#endif extern "C" int pthread_attr_init(void *attr); extern "C" int pthread_attr_destroy(void *attr); @@ -89,8 +99,13 @@ const int SIGFPE = 8; const int SIGSEGV = 11; const int SIGPIPE = 13; const int SIGTERM = 15; +#ifdef __mips__ +const int SIGBUS = 10; +const int SIGSYS = 12; +#else const int SIGBUS = 7; const int SIGSYS = 31; +#endif void *const MAP_FAILED = (void*)-1; const int PTHREAD_BARRIER_SERIAL_THREAD = -1; const int MAP_FIXED = 0x10; @@ -108,6 +123,9 @@ typedef void (*sighandler_t)(int sig); typedef void (*sigactionhandler_t)(int sig, my_siginfo_t *siginfo, void *uctx); struct sigaction_t { +#ifdef __mips__ + u32 sa_flags; +#endif union { sighandler_t sa_handler; sigactionhandler_t sa_sigaction; @@ -117,7 +135,9 @@ struct sigaction_t { __sanitizer_sigset_t sa_mask; #else __sanitizer_sigset_t sa_mask; +#ifndef __mips__ int sa_flags; +#endif void (*sa_restorer)(); #endif }; @@ -125,8 +145,13 @@ struct sigaction_t { const sighandler_t SIG_DFL = (sighandler_t)0; const sighandler_t SIG_IGN = (sighandler_t)1; const sighandler_t SIG_ERR = (sighandler_t)-1; +#ifdef __mips__ +const int SA_SIGINFO = 8; +const int SIG_SETMASK = 3; +#else const int SA_SIGINFO = 4; const int SIG_SETMASK = 2; +#endif namespace std { struct nothrow_t {}; @@ -157,7 +182,13 @@ static LibIgnore *libignore() { } void InitializeLibIgnore() { - libignore()->Init(*SuppressionContext::Get()); + const SuppressionContext &supp = *Suppressions(); + const uptr n = supp.SuppressionCount(); + for (uptr i = 0; i < n; i++) { + const Suppression *s = supp.SuppressionAt(i); + if (0 == internal_strcmp(s->type, kSuppressionLib)) + libignore()->AddIgnoredLibrary(s->templ); + } libignore()->OnLibraryLoaded(0); } @@ -1895,9 +1926,9 @@ static void CallUserSignalHandler(ThreadState *thr, bool sync, bool acquire, // signal; and it looks too fragile to intercept all ways to reraise a signal. if (flags()->report_bugs && !sync && sig != SIGTERM && errno != 99) { VarSizeStackTrace stack; - // Add 1 to pc because return address is expected, - // OutputReport() will undo this. - ObtainCurrentStack(thr, pc + 1, &stack); + // StackTrace::GetNestInstructionPc(pc) is used because return address is + // expected, OutputReport() will undo this. + ObtainCurrentStack(thr, StackTrace::GetNextInstructionPc(pc), &stack); ThreadRegistryLock l(ctx->thread_registry); ScopedReport rep(ReportTypeErrnoInSignal); if (!IsFiredSuppression(ctx, rep, stack)) { diff --git a/lib/tsan/rtl/tsan_interface_atomic.cc b/lib/tsan/rtl/tsan_interface_atomic.cc index 9b699511674a..27031991438c 100644 --- a/lib/tsan/rtl/tsan_interface_atomic.cc +++ b/lib/tsan/rtl/tsan_interface_atomic.cc @@ -33,14 +33,14 @@ typedef unsigned short a16; // NOLINT typedef unsigned int a32; typedef unsigned long long a64; // NOLINT #if !defined(SANITIZER_GO) && (defined(__SIZEOF_INT128__) \ - || (__clang_major__ * 100 + __clang_minor__ >= 302)) + || (__clang_major__ * 100 + __clang_minor__ >= 302)) && !defined(__mips64) __extension__ typedef __int128 a128; # define __TSAN_HAS_INT128 1 #else # define __TSAN_HAS_INT128 0 #endif -#ifndef SANITIZER_GO +#if !defined(SANITIZER_GO) && __TSAN_HAS_INT128 // Protects emulation of 128-bit atomic operations. static StaticSpinMutex mutex128; #endif @@ -125,7 +125,8 @@ template<typename T> T func_cas(volatile T *v, T cmp, T xch) { // Atomic ops are executed under tsan internal mutex, // here we assume that the atomic variables are not accessed // from non-instrumented code. -#if !defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16) && !defined(SANITIZER_GO) +#if !defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16) && !defined(SANITIZER_GO) \ + && __TSAN_HAS_INT128 a128 func_xchg(volatile a128 *v, a128 op) { SpinMutexLock lock(&mutex128); a128 cmp = *v; diff --git a/lib/tsan/rtl/tsan_platform.h b/lib/tsan/rtl/tsan_platform.h index 03f95694d26c..135e16027132 100644 --- a/lib/tsan/rtl/tsan_platform.h +++ b/lib/tsan/rtl/tsan_platform.h @@ -26,8 +26,9 @@ namespace __tsan { #if !defined(SANITIZER_GO) +#if defined(__x86_64__) /* -C/C++ on linux and freebsd +C/C++ on linux/x86_64 and freebsd/x86_64 0000 0000 1000 - 0100 0000 0000: main binary and/or MAP_32BIT mappings 0100 0000 0000 - 0200 0000 0000: - 0200 0000 0000 - 1000 0000 0000: shadow @@ -40,7 +41,6 @@ C/C++ on linux and freebsd 7e00 0000 0000 - 7e80 0000 0000: - 7e80 0000 0000 - 8000 0000 0000: modules and main thread stack */ - const uptr kMetaShadowBeg = 0x300000000000ull; const uptr kMetaShadowEnd = 0x400000000000ull; const uptr kTraceMemBeg = 0x600000000000ull; @@ -55,6 +55,38 @@ const uptr kHiAppMemBeg = 0x7e8000000000ull; const uptr kHiAppMemEnd = 0x800000000000ull; const uptr kAppMemMsk = 0x7c0000000000ull; const uptr kAppMemXor = 0x020000000000ull; +const uptr kVdsoBeg = 0xf000000000000000ull; +#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 +*/ +const uptr kMetaShadowBeg = 0x3000000000ull; +const uptr kMetaShadowEnd = 0x4000000000ull; +const uptr kTraceMemBeg = 0x6000000000ull; +const uptr kTraceMemEnd = 0x6200000000ull; +const uptr kShadowBeg = 0x1400000000ull; +const uptr kShadowEnd = 0x2400000000ull; +const uptr kHeapMemBeg = 0xfe00000000ull; +const uptr kHeapMemEnd = 0xff00000000ull; +const uptr kLoAppMemBeg = 0x0100000000ull; +const uptr kLoAppMemEnd = 0x0200000000ull; +const uptr kHiAppMemBeg = 0xff80000000ull; +const uptr kHiAppMemEnd = 0xffffffffffull; +const uptr kAppMemMsk = 0xfc00000000ull; +const uptr kAppMemXor = 0x0400000000ull; +const uptr kVdsoBeg = 0xfffff00000ull; +#endif ALWAYS_INLINE bool IsAppMem(uptr mem) { @@ -171,8 +203,8 @@ static USED uptr UserRegions[] = { 0000 1000 0000 - 00f8 0000 0000: - 00c0 0000 0000 - 00e0 0000 0000: heap 00e0 0000 0000 - 0100 0000 0000: - -0100 0000 0000 - 0380 0000 0000: shadow -0380 0000 0000 - 0560 0000 0000: - +0100 0000 0000 - 0500 0000 0000: shadow +0500 0000 0000 - 0560 0000 0000: - 0560 0000 0000 - 0760 0000 0000: traces 0760 0000 0000 - 07d0 0000 0000: metainfo (memory blocks and sync objects) 07d0 0000 0000 - 8000 0000 0000: - @@ -183,7 +215,7 @@ const uptr kMetaShadowEnd = 0x07d000000000ull; const uptr kTraceMemBeg = 0x056000000000ull; const uptr kTraceMemEnd = 0x076000000000ull; const uptr kShadowBeg = 0x010000000000ull; -const uptr kShadowEnd = 0x038000000000ull; +const uptr kShadowEnd = 0x050000000000ull; const uptr kAppMemBeg = 0x000000001000ull; const uptr kAppMemEnd = 0x00e000000000ull; @@ -205,21 +237,21 @@ bool IsMetaMem(uptr mem) { ALWAYS_INLINE uptr MemToShadow(uptr x) { DCHECK(IsAppMem(x)); - return ((x & ~(kShadowCell - 1)) * kShadowCnt) | kShadowBeg; + return ((x & ~(kShadowCell - 1)) * kShadowCnt) + kShadowBeg; } ALWAYS_INLINE u32 *MemToMeta(uptr x) { DCHECK(IsAppMem(x)); return (u32*)(((x & ~(kMetaShadowCell - 1)) / \ - kMetaShadowCell * kMetaShadowSize) | kMetaShadowEnd); + kMetaShadowCell * kMetaShadowSize) | kMetaShadowBeg); } ALWAYS_INLINE uptr ShadowToMem(uptr s) { CHECK(IsShadowMem(s)); // FIXME(dvyukov): this is most likely wrong as the mapping is not bijection. - return (x & ~kShadowBeg) / kShadowCnt; + return (s - kShadowBeg) / kShadowCnt; } static USED uptr UserRegions[] = { diff --git a/lib/tsan/rtl/tsan_platform_linux.cc b/lib/tsan/rtl/tsan_platform_linux.cc index 7bc28db296ec..659e8d8a8345 100644 --- a/lib/tsan/rtl/tsan_platform_linux.cc +++ b/lib/tsan/rtl/tsan_platform_linux.cc @@ -66,8 +66,6 @@ namespace __tsan { static uptr g_data_start; static uptr g_data_end; -const uptr kPageSize = 4096; - enum { MemTotal = 0, MemShadow = 1, @@ -173,7 +171,7 @@ static void MapRodata() { *p = kShadowRodata; internal_write(fd, marker.data(), marker.size()); // Map the file into memory. - uptr page = internal_mmap(0, kPageSize, PROT_READ | PROT_WRITE, + uptr page = internal_mmap(0, GetPageSizeCached(), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, fd, 0); if (internal_iserror(page)) { internal_close(fd); @@ -216,8 +214,15 @@ void InitializeShadowMemory() { // a program uses a small part of large mmap. On some programs // we see 20% memory usage reduction without huge pages for this range. // FIXME: don't use constants here. - NoHugePagesInRegion(MemToShadow(0x7f0000000000ULL), - 0x10000000000ULL * kShadowMultiplier); +#if defined(__x86_64__) + const uptr kMadviseRangeBeg = 0x7f0000000000ull; + const uptr kMadviseRangeSize = 0x010000000000ull; +#elif defined(__mips64) + const uptr kMadviseRangeBeg = 0xff00000000ull; + const uptr kMadviseRangeSize = 0x0100000000ull; +#endif + NoHugePagesInRegion(MemToShadow(kMadviseRangeBeg), + kMadviseRangeSize * kShadowMultiplier); if (common_flags()->use_madv_dontdump) DontDumpShadowMemory(kShadowBeg, kShadowEnd - kShadowBeg); DPrintf("memory shadow: %zx-%zx (%zuGB)\n", @@ -289,9 +294,9 @@ static void CheckAndProtect() { if (IsAppMem(p)) continue; if (p >= kHeapMemEnd && - p < kHeapMemEnd + PrimaryAllocator::AdditionalSize()) + p < HeapEnd()) continue; - if (p >= 0xf000000000000000ull) // vdso + if (p >= kVdsoBeg) // vdso break; Printf("FATAL: ThreadSanitizer: unexpected memory mapping %p-%p\n", p, end); Die(); @@ -304,7 +309,7 @@ static void CheckAndProtect() { // Protect the whole range for now, so that user does not map something here. ProtectRange(kTraceMemBeg, kTraceMemEnd); ProtectRange(kTraceMemEnd, kHeapMemBeg); - ProtectRange(kHeapMemEnd + PrimaryAllocator::AdditionalSize(), kHiAppMemBeg); + ProtectRange(HeapEnd(), kHiAppMemBeg); } #endif // #ifndef SANITIZER_GO diff --git a/lib/tsan/rtl/tsan_report.cc b/lib/tsan/rtl/tsan_report.cc index c22f12a1bfa5..7e69cb4ecfbc 100644 --- a/lib/tsan/rtl/tsan_report.cc +++ b/lib/tsan/rtl/tsan_report.cc @@ -356,8 +356,9 @@ void PrintStack(const ReportStack *ent) { SymbolizedStack *frame = ent->frames; for (int i = 0; frame; frame = frame->next, i++) { const AddressInfo &info = frame->info; - Printf(" %s()\n %s:%d +0x%zx\n", info.function, info.file, info.line, - (void *)info.module_offset); + Printf(" %s()\n %s:%d +0x%zx\n", info.function, + StripPathPrefix(info.file, common_flags()->strip_path_prefix), + info.line, (void *)info.module_offset); } } diff --git a/lib/tsan/rtl/tsan_rtl.cc b/lib/tsan/rtl/tsan_rtl.cc index b3320aad8038..b76f3e05dde6 100644 --- a/lib/tsan/rtl/tsan_rtl.cc +++ b/lib/tsan/rtl/tsan_rtl.cc @@ -67,8 +67,17 @@ static char thread_registry_placeholder[sizeof(ThreadRegistry)]; static ThreadContextBase *CreateThreadContext(u32 tid) { // Map thread trace when context is created. MapThreadTrace(GetThreadTrace(tid), TraceSize() * sizeof(Event)); - MapThreadTrace(GetThreadTraceHeader(tid), sizeof(Trace)); - new(ThreadTrace(tid)) Trace(); + const uptr hdr = GetThreadTraceHeader(tid); + MapThreadTrace(hdr, sizeof(Trace)); + new((void*)hdr) Trace(); + // We are going to use only a small part of the trace with the default + // value of history_size. However, the constructor writes to the whole trace. + // Unmap the unused part. + uptr hdr_end = hdr + sizeof(Trace); + hdr_end -= sizeof(TraceHeader) * (kTraceParts - TraceParts()); + hdr_end = RoundUp(hdr_end, GetPageSizeCached()); + if (hdr_end < hdr + sizeof(Trace)) + UnmapOrDie((void*)hdr_end, hdr + sizeof(Trace) - hdr_end); void *mem = internal_alloc(MBlockThreadContex, sizeof(ThreadContext)); return new(mem) ThreadContext(tid); } @@ -117,6 +126,7 @@ ThreadState::ThreadState(Context *ctx, int tid, int unique_id, u64 epoch, { } +#ifndef SANITIZER_GO static void MemoryProfiler(Context *ctx, fd_t fd, int i) { uptr n_threads; uptr n_running_threads; @@ -127,13 +137,11 @@ static void MemoryProfiler(Context *ctx, fd_t fd, int i) { } static void BackgroundThread(void *arg) { -#ifndef SANITIZER_GO // This is a non-initialized non-user thread, nothing to see here. // We don't use ScopedIgnoreInterceptors, because we want ignores to be // enabled even when the thread function exits (e.g. during pthread thread // shutdown code). cur_thread()->ignore_interceptors++; -#endif const u64 kMs2Ns = 1000 * 1000; fd_t mprof_fd = kInvalidFd; @@ -191,7 +199,6 @@ static void BackgroundThread(void *arg) { if (mprof_fd != kInvalidFd) MemoryProfiler(ctx, mprof_fd, i); -#ifndef SANITIZER_GO // Flush symbolizer cache if requested. if (flags()->flush_symbolizer_ms > 0) { u64 last = atomic_load(&ctx->last_symbolize_time_ns, @@ -203,7 +210,6 @@ static void BackgroundThread(void *arg) { atomic_store(&ctx->last_symbolize_time_ns, 0, memory_order_relaxed); } } -#endif } } @@ -211,13 +217,14 @@ static void StartBackgroundThread() { ctx->background_thread = internal_start_thread(&BackgroundThread, 0); } -#ifndef SANITIZER_GO +#ifndef __mips__ static void StopBackgroundThread() { atomic_store(&ctx->stop_background_thread, 1, memory_order_relaxed); internal_join_thread(ctx->background_thread); ctx->background_thread = 0; } #endif +#endif void DontNeedShadowFor(uptr addr, uptr size) { uptr shadow_beg = MemToShadow(addr); @@ -282,11 +289,11 @@ static void CheckShadowMapping() { if (p < beg || p >= end) continue; const uptr s = MemToShadow(p); - VPrintf(3, " checking pointer %p -> %p\n", p, s); + const uptr m = (uptr)MemToMeta(p); + VPrintf(3, " checking pointer %p: shadow=%p meta=%p\n", p, s, m); CHECK(IsAppMem(p)); CHECK(IsShadowMem(s)); CHECK_EQ(p & ~(kShadowCell - 1), ShadowToMem(s)); - const uptr m = (uptr)MemToMeta(p); CHECK(IsMetaMem(m)); } } @@ -325,11 +332,14 @@ void Initialize(ThreadState *thr) { #ifndef SANITIZER_GO InitializeLibIgnore(); Symbolizer::GetOrInit()->AddHooks(EnterSymbolizer, ExitSymbolizer); -#endif + // On MIPS, TSan initialization is run before + // __pthread_initialize_minimal_internal() is finished, so we can not spawn + // new threads. +#ifndef __mips__ StartBackgroundThread(); -#ifndef SANITIZER_GO SetSandboxingCallback(StopBackgroundThread); #endif +#endif if (common_flags()->detect_deadlocks) ctx->dd = DDetector::Create(flags()); @@ -394,8 +404,11 @@ int Finalize(ThreadState *thr) { failed = OnFinalize(failed); +#if TSAN_COLLECT_STATS StatAggregate(ctx->stat, thr->stat); StatOutput(ctx->stat); +#endif + return failed ? flags()->exitcode : 0; } @@ -419,7 +432,7 @@ void ForkChildAfter(ThreadState *thr, uptr pc) { VPrintf(1, "ThreadSanitizer: forked new process with pid %d," " parent had %d threads\n", (int)internal_getpid(), (int)nthread); if (nthread == 1) { - internal_start_thread(&BackgroundThread, 0); + StartBackgroundThread(); } else { // We've just forked a multi-threaded process. We cannot reasonably function // after that (some mutexes may be locked before fork). So just enable @@ -826,7 +839,7 @@ static void MemoryRangeSet(ThreadState *thr, uptr pc, uptr addr, uptr size, } } else { // The region is big, reset only beginning and end. - const uptr kPageSize = 4096; + const uptr kPageSize = GetPageSizeCached(); u64 *begin = (u64*)MemToShadow(addr); u64 *end = begin + size / kShadowCell * kShadowCnt; u64 *p = begin; diff --git a/lib/tsan/rtl/tsan_rtl.h b/lib/tsan/rtl/tsan_rtl.h index 768e8307fcc8..7a60e5c55af4 100644 --- a/lib/tsan/rtl/tsan_rtl.h +++ b/lib/tsan/rtl/tsan_rtl.h @@ -54,8 +54,21 @@ namespace __tsan { #ifndef SANITIZER_GO struct MapUnmapCallback; +#ifdef __mips64 +static const uptr kAllocatorSpace = 0; +static const uptr kAllocatorSize = SANITIZER_MMAP_RANGE_SIZE; +static const uptr kAllocatorRegionSizeLog = 20; +static const uptr kAllocatorNumRegions = + kAllocatorSize >> kAllocatorRegionSizeLog; +typedef TwoLevelByteMap<(kAllocatorNumRegions >> 12), 1 << 12, + MapUnmapCallback> ByteMap; +typedef SizeClassAllocator32<kAllocatorSpace, kAllocatorSize, 0, + CompactSizeClassMap, kAllocatorRegionSizeLog, ByteMap, + MapUnmapCallback> PrimaryAllocator; +#else typedef SizeClassAllocator64<kHeapMemBeg, kHeapMemEnd - kHeapMemBeg, 0, DefaultSizeClassMap, MapUnmapCallback> PrimaryAllocator; +#endif typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache; typedef LargeMmapAllocator<MapUnmapCallback> SecondaryAllocator; typedef CombinedAllocator<PrimaryAllocator, AllocatorCache, @@ -351,7 +364,9 @@ struct ThreadState { Vector<JmpBuf> jmp_bufs; int ignore_interceptors; #endif +#if TSAN_COLLECT_STATS u64 stat[StatCnt]; +#endif const int tid; const int unique_id; bool in_symbolizer; @@ -365,7 +380,9 @@ struct ThreadState { const uptr tls_size; ThreadContext *tctx; +#if SANITIZER_DEBUG && !SANITIZER_GO InternalDeadlockDetector internal_deadlock_detector; +#endif DDPhysicalThread *dd_pt; DDLogicalThread *dd_lt; @@ -539,15 +556,20 @@ void ObtainCurrentStack(ThreadState *thr, uptr toppc, StackTraceTy *stack) { } +#if TSAN_COLLECT_STATS void StatAggregate(u64 *dst, u64 *src); void StatOutput(u64 *stat); +#endif + void ALWAYS_INLINE StatInc(ThreadState *thr, StatType typ, u64 n = 1) { - if (kCollectStats) - thr->stat[typ] += n; +#if TSAN_COLLECT_STATS + thr->stat[typ] += n; +#endif } void ALWAYS_INLINE StatSet(ThreadState *thr, StatType typ, u64 n) { - if (kCollectStats) - thr->stat[typ] = n; +#if TSAN_COLLECT_STATS + thr->stat[typ] = n; +#endif } void MapShadow(uptr addr, uptr size); @@ -729,6 +751,16 @@ void ALWAYS_INLINE TraceAddEvent(ThreadState *thr, FastState fs, *evp = ev; } +#ifndef SANITIZER_GO +uptr ALWAYS_INLINE HeapEnd() { +#if SANITIZER_CAN_USE_ALLOCATOR64 + return kHeapMemEnd + PrimaryAllocator::AdditionalSize(); +#else + return kHeapMemEnd; +#endif +} +#endif + } // namespace __tsan #endif // TSAN_RTL_H diff --git a/lib/tsan/rtl/tsan_rtl_report.cc b/lib/tsan/rtl/tsan_rtl_report.cc index d1621454242c..dc9438e6371b 100644 --- a/lib/tsan/rtl/tsan_rtl_report.cc +++ b/lib/tsan/rtl/tsan_rtl_report.cc @@ -112,16 +112,10 @@ static ReportStack *SymbolizeStack(StackTrace trace) { for (uptr si = 0; si < trace.size; si++) { const uptr pc = trace.trace[si]; uptr pc1 = pc; -#ifndef SANITIZER_GO // We obtain the return address, but we're interested in the previous // instruction. if ((pc & kExternalPCBit) == 0) pc1 = StackTrace::GetPreviousInstructionPc(pc); -#else - // FIXME(dvyukov): Go sometimes uses address of a function as top pc. - if (si != trace.size - 1) - pc1 -= 1; -#endif SymbolizedStack *ent = SymbolizeCode(pc1); CHECK_NE(ent, 0); SymbolizedStack *last = ent; diff --git a/lib/tsan/rtl/tsan_rtl_thread.cc b/lib/tsan/rtl/tsan_rtl_thread.cc index e026217ed171..8ed1fbf2edae 100644 --- a/lib/tsan/rtl/tsan_rtl_thread.cc +++ b/lib/tsan/rtl/tsan_rtl_thread.cc @@ -145,7 +145,9 @@ void ThreadContext::OnFinished() { AllocatorThreadFinish(thr); #endif thr->~ThreadState(); +#if TSAN_COLLECT_STATS StatAggregate(ctx->stat, thr->stat); +#endif thr = 0; } @@ -239,6 +241,7 @@ void ThreadStart(ThreadState *thr, int tid, uptr os_id) { uptr stk_size = 0; uptr tls_addr = 0; uptr tls_size = 0; +#ifndef SANITIZER_GO GetThreadStackAndTls(tid == 0, &stk_addr, &stk_size, &tls_addr, &tls_size); if (tid) { @@ -259,6 +262,7 @@ void ThreadStart(ThreadState *thr, int tid, uptr os_id) { thr_end, tls_addr + tls_size - thr_end); } } +#endif ThreadRegistry *tr = ctx->thread_registry; OnStartedArgs args = { thr, stk_addr, stk_size, tls_addr, tls_size }; diff --git a/lib/tsan/rtl/tsan_stat.cc b/lib/tsan/rtl/tsan_stat.cc index 350a2ba48253..15fa43d6f8a1 100644 --- a/lib/tsan/rtl/tsan_stat.cc +++ b/lib/tsan/rtl/tsan_stat.cc @@ -15,17 +15,14 @@ namespace __tsan { +#if TSAN_COLLECT_STATS + void StatAggregate(u64 *dst, u64 *src) { - if (!kCollectStats) - return; for (int i = 0; i < StatCnt; i++) dst[i] += src[i]; } void StatOutput(u64 *stat) { - if (!kCollectStats) - return; - stat[StatShadowNonZero] = stat[StatShadowProcessed] - stat[StatShadowZero]; static const char *name[StatCnt] = {}; @@ -176,4 +173,6 @@ void StatOutput(u64 *stat) { Printf("%s: %16zu\n", name[i], (uptr)stat[i]); } +#endif + } // namespace __tsan diff --git a/lib/tsan/rtl/tsan_suppressions.cc b/lib/tsan/rtl/tsan_suppressions.cc index 299fc80fd262..5413f04af1d2 100644 --- a/lib/tsan/rtl/tsan_suppressions.cc +++ b/lib/tsan/rtl/tsan_suppressions.cc @@ -41,63 +41,74 @@ extern "C" const char *WEAK __tsan_default_suppressions() { namespace __tsan { -static bool suppressions_inited = false; +ALIGNED(64) static char suppression_placeholder[sizeof(SuppressionContext)]; +static SuppressionContext *suppression_ctx = nullptr; +static const char *kSuppressionTypes[] = { + kSuppressionRace, kSuppressionMutex, kSuppressionThread, + kSuppressionSignal, kSuppressionLib, kSuppressionDeadlock}; void InitializeSuppressions() { - CHECK(!suppressions_inited); - SuppressionContext::InitIfNecessary(); + CHECK_EQ(nullptr, suppression_ctx); + suppression_ctx = new (suppression_placeholder) // NOLINT + SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes)); + suppression_ctx->ParseFromFile(flags()->suppressions); #ifndef SANITIZER_GO - SuppressionContext::Get()->Parse(__tsan_default_suppressions()); - SuppressionContext::Get()->Parse(std_suppressions); + suppression_ctx->Parse(__tsan_default_suppressions()); + suppression_ctx->Parse(std_suppressions); #endif - suppressions_inited = true; } -SuppressionType conv(ReportType typ) { +SuppressionContext *Suppressions() { + CHECK(suppression_ctx); + return suppression_ctx; +} + +static const char *conv(ReportType typ) { if (typ == ReportTypeRace) - return SuppressionRace; + return kSuppressionRace; else if (typ == ReportTypeVptrRace) - return SuppressionRace; + return kSuppressionRace; else if (typ == ReportTypeUseAfterFree) - return SuppressionRace; + return kSuppressionRace; else if (typ == ReportTypeVptrUseAfterFree) - return SuppressionRace; + return kSuppressionRace; else if (typ == ReportTypeThreadLeak) - return SuppressionThread; + return kSuppressionThread; else if (typ == ReportTypeMutexDestroyLocked) - return SuppressionMutex; + return kSuppressionMutex; else if (typ == ReportTypeMutexDoubleLock) - return SuppressionMutex; + return kSuppressionMutex; else if (typ == ReportTypeMutexBadUnlock) - return SuppressionMutex; + return kSuppressionMutex; else if (typ == ReportTypeMutexBadReadLock) - return SuppressionMutex; + return kSuppressionMutex; else if (typ == ReportTypeMutexBadReadUnlock) - return SuppressionMutex; + return kSuppressionMutex; else if (typ == ReportTypeSignalUnsafe) - return SuppressionSignal; + return kSuppressionSignal; else if (typ == ReportTypeErrnoInSignal) - return SuppressionNone; + return kSuppressionNone; else if (typ == ReportTypeDeadlock) - return SuppressionDeadlock; + return kSuppressionDeadlock; Printf("ThreadSanitizer: unknown report type %d\n", typ), Die(); } uptr IsSuppressed(ReportType typ, const ReportStack *stack, Suppression **sp) { - if (!SuppressionContext::Get()->SuppressionCount() || stack == 0 || + CHECK(suppression_ctx); + if (!suppression_ctx->SuppressionCount() || stack == 0 || !stack->suppressable) return 0; - SuppressionType stype = conv(typ); - if (stype == SuppressionNone) + const char *stype = conv(typ); + if (0 == internal_strcmp(stype, kSuppressionNone)) return 0; Suppression *s; for (const SymbolizedStack *frame = stack->frames; frame; frame = frame->next) { const AddressInfo &info = frame->info; - if (SuppressionContext::Get()->Match(info.function, stype, &s) || - SuppressionContext::Get()->Match(info.file, stype, &s) || - SuppressionContext::Get()->Match(info.module, stype, &s)) { + if (suppression_ctx->Match(info.function, stype, &s) || + suppression_ctx->Match(info.file, stype, &s) || + suppression_ctx->Match(info.module, stype, &s)) { DPrintf("ThreadSanitizer: matched suppression '%s'\n", s->templ); s->hit_count++; *sp = s; @@ -108,16 +119,17 @@ uptr IsSuppressed(ReportType typ, const ReportStack *stack, Suppression **sp) { } uptr IsSuppressed(ReportType typ, const ReportLocation *loc, Suppression **sp) { - if (!SuppressionContext::Get()->SuppressionCount() || loc == 0 || + CHECK(suppression_ctx); + if (!suppression_ctx->SuppressionCount() || loc == 0 || loc->type != ReportLocationGlobal || !loc->suppressable) return 0; - SuppressionType stype = conv(typ); - if (stype == SuppressionNone) + const char *stype = conv(typ); + if (0 == internal_strcmp(stype, kSuppressionNone)) return 0; Suppression *s; const DataInfo &global = loc->global; - if (SuppressionContext::Get()->Match(global.name, stype, &s) || - SuppressionContext::Get()->Match(global.module, stype, &s)) { + if (suppression_ctx->Match(global.name, stype, &s) || + suppression_ctx->Match(global.module, stype, &s)) { DPrintf("ThreadSanitizer: matched suppression '%s'\n", s->templ); s->hit_count++; *sp = s; @@ -128,7 +140,8 @@ uptr IsSuppressed(ReportType typ, const ReportLocation *loc, Suppression **sp) { void PrintMatchedSuppressions() { InternalMmapVector<Suppression *> matched(1); - SuppressionContext::Get()->GetMatched(&matched); + CHECK(suppression_ctx); + suppression_ctx->GetMatched(&matched); if (!matched.size()) return; int hit_count = 0; @@ -137,8 +150,8 @@ void PrintMatchedSuppressions() { Printf("ThreadSanitizer: Matched %d suppressions (pid=%d):\n", hit_count, (int)internal_getpid()); for (uptr i = 0; i < matched.size(); i++) { - Printf("%d %s:%s\n", matched[i]->hit_count, - SuppressionTypeString(matched[i]->type), matched[i]->templ); + Printf("%d %s:%s\n", matched[i]->hit_count, matched[i]->type, + matched[i]->templ); } } } // namespace __tsan diff --git a/lib/tsan/rtl/tsan_suppressions.h b/lib/tsan/rtl/tsan_suppressions.h index c618b3db4c2d..e6d279c33a4e 100644 --- a/lib/tsan/rtl/tsan_suppressions.h +++ b/lib/tsan/rtl/tsan_suppressions.h @@ -18,7 +18,16 @@ namespace __tsan { +const char kSuppressionNone[] = "none"; +const char kSuppressionRace[] = "race"; +const char kSuppressionMutex[] = "mutex"; +const char kSuppressionThread[] = "thread"; +const char kSuppressionSignal[] = "signal"; +const char kSuppressionLib[] = "called_from_lib"; +const char kSuppressionDeadlock[] = "deadlock"; + void InitializeSuppressions(); +SuppressionContext *Suppressions(); void PrintMatchedSuppressions(); uptr IsSuppressed(ReportType typ, const ReportStack *stack, Suppression **sp); uptr IsSuppressed(ReportType typ, const ReportLocation *loc, Suppression **sp); diff --git a/lib/tsan/rtl/tsan_trace.h b/lib/tsan/rtl/tsan_trace.h index 1da8752f6fa7..2569c7e42a47 100644 --- a/lib/tsan/rtl/tsan_trace.h +++ b/lib/tsan/rtl/tsan_trace.h @@ -20,9 +20,9 @@ namespace __tsan { -const int kTracePartSizeBits = 14; +const int kTracePartSizeBits = 13; const int kTracePartSize = 1 << kTracePartSizeBits; -const int kTraceParts = 4 * 1024 * 1024 / kTracePartSize; +const int kTraceParts = 2 * 1024 * 1024 / kTracePartSize; const int kTraceSize = kTracePartSize * kTraceParts; // Must fit into 3 bits. @@ -54,13 +54,15 @@ struct TraceHeader { }; struct Trace { - TraceHeader headers[kTraceParts]; Mutex mtx; #ifndef SANITIZER_GO // Must be last to catch overflow as paging fault. // Go shadow stack is dynamically allocated. uptr shadow_stack[kShadowStackSize]; #endif + // Must be the last field, because we unmap the unused part in + // CreateThreadContext. + TraceHeader headers[kTraceParts]; Trace() : mtx(MutexTypeTrace, StatMtxTrace) { diff --git a/lib/tsan/tests/CMakeLists.txt b/lib/tsan/tests/CMakeLists.txt index cb7e5374ec8a..e0c3f8a1a6d8 100644 --- a/lib/tsan/tests/CMakeLists.txt +++ b/lib/tsan/tests/CMakeLists.txt @@ -34,26 +34,28 @@ endmacro() macro(add_tsan_unittest testname) # Build unit tests only for 64-bit Linux. - if(UNIX AND NOT APPLE AND CAN_TARGET_x86_64) - parse_arguments(TEST "SOURCES;HEADERS" "" ${ARGN}) - set(TEST_OBJECTS) - foreach(SOURCE ${TEST_SOURCES} ${COMPILER_RT_GTEST_SOURCE}) - tsan_compile(TEST_OBJECTS ${SOURCE} x86_64 ${TEST_HEADERS}) + if(UNIX AND NOT APPLE) + foreach(arch ${TSAN_SUPPORTED_ARCH}) + parse_arguments(TEST "SOURCES;HEADERS" "" ${ARGN}) + set(TEST_OBJECTS) + foreach(SOURCE ${TEST_SOURCES} ${COMPILER_RT_GTEST_SOURCE}) + tsan_compile(TEST_OBJECTS ${SOURCE} ${arch} ${TEST_HEADERS}) + endforeach() + get_target_flags_for_arch(${arch} TARGET_LINK_FLAGS) + set(TEST_DEPS ${TEST_OBJECTS}) + if(NOT COMPILER_RT_STANDALONE_BUILD) + list(APPEND TEST_DEPS tsan) + endif() + # FIXME: Looks like we should link TSan with just-built runtime, + # and not rely on -fsanitize=thread, as these tests are essentially + # unit tests. + add_compiler_rt_test(TsanUnitTests ${testname} + OBJECTS ${TEST_OBJECTS} + DEPS ${TEST_DEPS} + LINK_FLAGS ${TARGET_LINK_FLAGS} + -fsanitize=thread + -lstdc++ -lm) endforeach() - get_target_flags_for_arch(${arch} TARGET_LINK_FLAGS) - set(TEST_DEPS ${TEST_OBJECTS}) - if(NOT COMPILER_RT_STANDALONE_BUILD) - list(APPEND TEST_DEPS tsan) - endif() - # FIXME: Looks like we should link TSan with just-built runtime, - # and not rely on -fsanitize=thread, as these tests are essentially - # unit tests. - add_compiler_rt_test(TsanUnitTests ${testname} - OBJECTS ${TEST_OBJECTS} - DEPS ${TEST_DEPS} - LINK_FLAGS ${TARGET_LINK_FLAGS} - -fsanitize=thread - -lstdc++ -lm) endif() endmacro() |