aboutsummaryrefslogtreecommitdiff
path: root/lib/tsan
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2015-02-22 22:43:40 +0000
committerDimitry Andric <dim@FreeBSD.org>2015-02-22 22:43:40 +0000
commitcd2dd3df15523e2be8d2bbace27641d6ac9fa40d (patch)
treefbdacaec253cc5ceee88cb44de5545fa32c8bd67 /lib/tsan
parent476c4db3dc56bee43df384704c75ccc71cfa7a1d (diff)
downloadsrc-cd2dd3df15523e2be8d2bbace27641d6ac9fa40d.tar.gz
src-cd2dd3df15523e2be8d2bbace27641d6ac9fa40d.zip
Import compiler-rt trunk r230183.vendor/compiler-rt/compiler-rt-r230183
Notes
Notes: svn path=/vendor/compiler-rt/dist/; revision=279192 svn path=/vendor/compiler-rt/compiler-rt-r230183/; revision=279193; tag=vendor/compiler-rt/compiler-rt-r230183
Diffstat (limited to 'lib/tsan')
-rw-r--r--lib/tsan/CMakeLists.txt55
-rw-r--r--lib/tsan/Makefile.mk18
-rw-r--r--lib/tsan/dd/dd_rtl.cc8
-rw-r--r--lib/tsan/go/build.bat4
-rwxr-xr-xlib/tsan/go/buildgo.sh2
-rw-r--r--lib/tsan/rtl/Makefile.mk25
-rw-r--r--lib/tsan/rtl/tsan_defs.h21
-rw-r--r--lib/tsan/rtl/tsan_flags.cc2
-rw-r--r--lib/tsan/rtl/tsan_flags.inc3
-rw-r--r--lib/tsan/rtl/tsan_interceptors.cc39
-rw-r--r--lib/tsan/rtl/tsan_interface_atomic.cc7
-rw-r--r--lib/tsan/rtl/tsan_platform.h48
-rw-r--r--lib/tsan/rtl/tsan_platform_linux.cc21
-rw-r--r--lib/tsan/rtl/tsan_report.cc5
-rw-r--r--lib/tsan/rtl/tsan_rtl.cc39
-rw-r--r--lib/tsan/rtl/tsan_rtl.h40
-rw-r--r--lib/tsan/rtl/tsan_rtl_report.cc6
-rw-r--r--lib/tsan/rtl/tsan_rtl_thread.cc4
-rw-r--r--lib/tsan/rtl/tsan_stat.cc9
-rw-r--r--lib/tsan/rtl/tsan_suppressions.cc81
-rw-r--r--lib/tsan/rtl/tsan_suppressions.h9
-rw-r--r--lib/tsan/rtl/tsan_trace.h8
-rw-r--r--lib/tsan/tests/CMakeLists.txt40
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()