tsan: remove in_rtl counter

This is intended to address the following problem.
Episodically we see CHECK-failures when recursive interceptors call back into user code. Effectively we are not "in_rtl" at this point, but it's very complicated and fragile to properly maintain in_rtl property. Instead get rid of it. It was used mostly for sanity CHECKs, which basically never uncover real problems.
Instead introduce ignore_interceptors flag, which is used in very few narrow places to disable recursive interceptors (e.g. during runtime initialization).

llvm-svn: 197979
This commit is contained in:
Dmitry Vyukov 2013-12-24 12:55:56 +00:00
parent 27aea0b0b7
commit ce3721057d
23 changed files with 149 additions and 188 deletions

View File

@ -70,12 +70,14 @@ presubmit:
# Release build with clang. # Release build with clang.
$(MAKE) -f Makefile.old clean $(MAKE) -f Makefile.old clean
$(MAKE) -f Makefile.old run DEBUG=0 -j 16 CC=$(CLANG) CXX=$(CLANG)++ $(MAKE) -f Makefile.old run DEBUG=0 -j 16 CC=$(CLANG) CXX=$(CLANG)++
./check_memcpy.sh
# Debug build with gcc # Debug build with gcc
$(MAKE) -f Makefile.old clean $(MAKE) -f Makefile.old clean
$(MAKE) -f Makefile.old run DEBUG=1 -j 16 CC=gcc CXX=g++ $(MAKE) -f Makefile.old run DEBUG=1 -j 16 CC=gcc CXX=g++
# Release build with gcc # Release build with gcc
$(MAKE) -f Makefile.old clean $(MAKE) -f Makefile.old clean
$(MAKE) -f Makefile.old run DEBUG=0 -j 16 CC=gcc CXX=g++ $(MAKE) -f Makefile.old run DEBUG=0 -j 16 CC=gcc CXX=g++
./check_memcpy.sh
./check_analyze.sh ./check_analyze.sh
# Sanity check for Go runtime # Sanity check for Go runtime
(cd go && ./buildgo.sh) (cd go && ./buildgo.sh)

View File

@ -0,0 +1,23 @@
#!/bin/bash
# Ensure that tsan runtime does not contain compiler-emitted memcpy and memset calls.
set -eu
ROOTDIR=$(dirname $0)
: ${CXX:=clang++}
CFLAGS="-fsanitize=thread -fPIE -O1 -g"
LDFLAGS="-pie -lpthread -ldl -lrt -lm -Wl,--whole-archive $ROOTDIR/rtl/libtsan.a -Wl,--no-whole-archive"
SRC=$ROOTDIR/lit_tests/simple_race.cc
OBJ=$SRC.o
EXE=$SRC.exe
$CXX $SRC $CFLAGS -c -o $OBJ
$CXX $OBJ $LDFLAGS -o $EXE
NCALL=$(objdump -d $EXE | egrep "callq .*__interceptor_mem(cpy|set)" | wc -l)
if [ "$NCALL" != "0" ]; then
echo FAIL: found $NCALL memcpy/memset calls
exit 1
fi

View File

@ -88,17 +88,13 @@ static ThreadState *AllocGoroutine() {
void __tsan_init(ThreadState **thrp) { void __tsan_init(ThreadState **thrp) {
ThreadState *thr = AllocGoroutine(); ThreadState *thr = AllocGoroutine();
main_thr = *thrp = thr; main_thr = *thrp = thr;
thr->in_rtl++;
Initialize(thr); Initialize(thr);
thr->in_rtl--;
} }
void __tsan_fini() { void __tsan_fini() {
// FIXME: Not necessary thread 0. // FIXME: Not necessary thread 0.
ThreadState *thr = main_thr; ThreadState *thr = main_thr;
thr->in_rtl++;
int res = Finalize(thr); int res = Finalize(thr);
thr->in_rtl--;
exit(res); exit(res);
} }
@ -137,9 +133,7 @@ void __tsan_func_exit(ThreadState *thr) {
void __tsan_malloc(ThreadState *thr, void *p, uptr sz, void *pc) { void __tsan_malloc(ThreadState *thr, void *p, uptr sz, void *pc) {
if (thr == 0) // probably before __tsan_init() if (thr == 0) // probably before __tsan_init()
return; return;
thr->in_rtl++;
MemoryResetRange(thr, (uptr)pc, (uptr)p, sz); MemoryResetRange(thr, (uptr)pc, (uptr)p, sz);
thr->in_rtl--;
} }
void __tsan_free(void *p) { void __tsan_free(void *p) {
@ -149,37 +143,25 @@ void __tsan_free(void *p) {
void __tsan_go_start(ThreadState *parent, ThreadState **pthr, void *pc) { void __tsan_go_start(ThreadState *parent, ThreadState **pthr, void *pc) {
ThreadState *thr = AllocGoroutine(); ThreadState *thr = AllocGoroutine();
*pthr = thr; *pthr = thr;
thr->in_rtl++;
parent->in_rtl++;
int goid = ThreadCreate(parent, (uptr)pc, 0, true); int goid = ThreadCreate(parent, (uptr)pc, 0, true);
ThreadStart(thr, goid, 0); ThreadStart(thr, goid, 0);
parent->in_rtl--;
thr->in_rtl--;
} }
void __tsan_go_end(ThreadState *thr) { void __tsan_go_end(ThreadState *thr) {
thr->in_rtl++;
ThreadFinish(thr); ThreadFinish(thr);
thr->in_rtl--;
internal_free(thr); internal_free(thr);
} }
void __tsan_acquire(ThreadState *thr, void *addr) { void __tsan_acquire(ThreadState *thr, void *addr) {
thr->in_rtl++;
Acquire(thr, 0, (uptr)addr); Acquire(thr, 0, (uptr)addr);
thr->in_rtl--;
} }
void __tsan_release(ThreadState *thr, void *addr) { void __tsan_release(ThreadState *thr, void *addr) {
thr->in_rtl++;
ReleaseStore(thr, 0, (uptr)addr); ReleaseStore(thr, 0, (uptr)addr);
thr->in_rtl--;
} }
void __tsan_release_merge(ThreadState *thr, void *addr) { void __tsan_release_merge(ThreadState *thr, void *addr) {
thr->in_rtl++;
Release(thr, 0, (uptr)addr); Release(thr, 0, (uptr)addr);
thr->in_rtl--;
} }
void __tsan_finalizer_goroutine(ThreadState *thr) { void __tsan_finalizer_goroutine(ThreadState *thr) {

View File

@ -0,0 +1,52 @@
// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
static int malloc_count;
static int free_count;
extern "C" {
void __tsan_malloc_hook(void *ptr, size_t size) {
(void)ptr;
(void)size;
__sync_fetch_and_add(&malloc_count, 1);
}
void __tsan_free_hook(void *ptr) {
(void)ptr;
__sync_fetch_and_add(&free_count, 1);
}
}
void *Thread1(void *x) {
((int*)x)[0]++;
return 0;
}
void *Thread2(void *x) {
sleep(1);
((int*)x)[0]++;
return 0;
}
int main() {
int *x = new int;
pthread_t t[2];
pthread_create(&t[0], 0, Thread1, x);
pthread_create(&t[1], 0, Thread2, x);
pthread_join(t[0], 0);
pthread_join(t[1], 0);
delete x;
if (malloc_count == 0 || free_count == 0) {
fprintf(stderr, "FAILED %d %d\n", malloc_count, free_count);
exit(1);
}
fprintf(stderr, "DONE\n");
}
// CHECK: WARNING: ThreadSanitizer: data race
// CHECK-NOT: FAILED
// CHECK: DONE

View File

@ -144,7 +144,6 @@ void InitializeLibIgnore() {
static SignalContext *SigCtx(ThreadState *thr) { static SignalContext *SigCtx(ThreadState *thr) {
SignalContext *ctx = (SignalContext*)thr->signal_ctx; SignalContext *ctx = (SignalContext*)thr->signal_ctx;
if (ctx == 0 && thr->is_alive) { if (ctx == 0 && thr->is_alive) {
ScopedInRtl in_rtl;
ctx = (SignalContext*)MmapOrDie(sizeof(*ctx), "SignalContext"); ctx = (SignalContext*)MmapOrDie(sizeof(*ctx), "SignalContext");
MemoryResetRange(thr, (uptr)&SigCtx, (uptr)ctx, sizeof(*ctx)); MemoryResetRange(thr, (uptr)&SigCtx, (uptr)ctx, sizeof(*ctx));
thr->signal_ctx = ctx; thr->signal_ctx = ctx;
@ -161,7 +160,6 @@ class ScopedInterceptor {
private: private:
ThreadState *const thr_; ThreadState *const thr_;
const uptr pc_; const uptr pc_;
const int in_rtl_;
bool in_ignored_lib_; bool in_ignored_lib_;
}; };
@ -169,16 +167,12 @@ ScopedInterceptor::ScopedInterceptor(ThreadState *thr, const char *fname,
uptr pc) uptr pc)
: thr_(thr) : thr_(thr)
, pc_(pc) , pc_(pc)
, in_rtl_(thr->in_rtl)
, in_ignored_lib_(false) { , in_ignored_lib_(false) {
if (thr_->in_rtl == 0) { if (!thr_->ignore_interceptors) {
Initialize(thr); Initialize(thr);
FuncEntry(thr, pc); FuncEntry(thr, pc);
thr_->in_rtl++;
DPrintf("#%d: intercept %s()\n", thr_->tid, fname);
} else {
thr_->in_rtl++;
} }
DPrintf("#%d: intercept %s()\n", thr_->tid, fname);
if (!thr_->in_ignored_lib && libignore()->IsIgnored(pc)) { if (!thr_->in_ignored_lib && libignore()->IsIgnored(pc)) {
in_ignored_lib_ = true; in_ignored_lib_ = true;
thr_->in_ignored_lib = true; thr_->in_ignored_lib = true;
@ -191,12 +185,10 @@ ScopedInterceptor::~ScopedInterceptor() {
thr_->in_ignored_lib = false; thr_->in_ignored_lib = false;
ThreadIgnoreEnd(thr_, pc_); ThreadIgnoreEnd(thr_, pc_);
} }
thr_->in_rtl--; if (!thr_->ignore_interceptors) {
if (thr_->in_rtl == 0) {
FuncExit(thr_); FuncExit(thr_);
ProcessPendingSignals(thr_); ProcessPendingSignals(thr_);
} }
CHECK_EQ(in_rtl_, thr_->in_rtl);
} }
#define SCOPED_INTERCEPTOR_RAW(func, ...) \ #define SCOPED_INTERCEPTOR_RAW(func, ...) \
@ -215,7 +207,7 @@ ScopedInterceptor::~ScopedInterceptor() {
Printf("FATAL: ThreadSanitizer: failed to intercept %s\n", #func); \ Printf("FATAL: ThreadSanitizer: failed to intercept %s\n", #func); \
Die(); \ Die(); \
} \ } \
if (thr->in_rtl > 1 || thr->in_ignored_lib) \ if (thr->ignore_interceptors || thr->in_ignored_lib) \
return REAL(func)(__VA_ARGS__); \ return REAL(func)(__VA_ARGS__); \
/**/ /**/
@ -235,6 +227,13 @@ struct BlockingCall {
} }
SignalContext *ctx; SignalContext *ctx;
// When we are in a "blocking call", we process signals asynchronously
// (right when they arrive). In this context we do not expect to be
// executing any user/runtime code. The known interceptor sequence when
// this is not true is: pthread_join -> munmap(stack). It's fine
// to ignore munmap in this case -- we handle stack shadow separately.
ScopedIgnoreInterceptors ignore_interceptors;
}; };
TSAN_INTERCEPTOR(unsigned, sleep, unsigned sec) { TSAN_INTERCEPTOR(unsigned, sleep, unsigned sec) {
@ -260,22 +259,14 @@ TSAN_INTERCEPTOR(int, nanosleep, void *req, void *rem) {
TSAN_INTERCEPTOR(void*, dlopen, const char *filename, int flag) { TSAN_INTERCEPTOR(void*, dlopen, const char *filename, int flag) {
SCOPED_INTERCEPTOR_RAW(dlopen, filename, 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); void *res = REAL(dlopen)(filename, flag);
thr->in_rtl = 1;
libignore()->OnLibraryLoaded(filename); libignore()->OnLibraryLoaded(filename);
return res; return res;
} }
TSAN_INTERCEPTOR(int, dlclose, void *handle) { TSAN_INTERCEPTOR(int, dlclose, void *handle) {
SCOPED_INTERCEPTOR_RAW(dlclose, 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); int res = REAL(dlclose)(handle);
thr->in_rtl = 1;
libignore()->OnLibraryUnloaded(); libignore()->OnLibraryUnloaded();
return res; return res;
} }
@ -303,7 +294,6 @@ class AtExitContext {
} }
void exit(ThreadState *thr, uptr pc) { void exit(ThreadState *thr, uptr pc) {
CHECK_EQ(thr->in_rtl, 0);
for (;;) { for (;;) {
atexit_t f = 0; atexit_t f = 0;
void *arg = 0; void *arg = 0;
@ -315,14 +305,12 @@ class AtExitContext {
f = stack_[pos_]; f = stack_[pos_];
arg = args_[pos_]; arg = args_[pos_];
is_on_exit = is_on_exits_[pos_]; is_on_exit = is_on_exits_[pos_];
ScopedInRtl in_rtl;
Acquire(thr, pc, (uptr)this); Acquire(thr, pc, (uptr)this);
} }
} }
if (f == 0) if (f == 0)
break; break;
DPrintf("#%d: executing atexit func %p\n", thr->tid, f); DPrintf("#%d: executing atexit func %p\n", thr->tid, f);
CHECK_EQ(thr->in_rtl, 0);
if (is_on_exit) if (is_on_exit)
((void(*)(int status, void *arg))f)(0, arg); ((void(*)(int status, void *arg))f)(0, arg);
else else
@ -415,7 +403,6 @@ static void LongJmp(ThreadState *thr, uptr *env) {
// FIXME: put everything below into a common extern "C" block? // FIXME: put everything below into a common extern "C" block?
extern "C" void __tsan_setjmp(uptr sp, uptr mangled_sp) { extern "C" void __tsan_setjmp(uptr sp, uptr mangled_sp) {
ScopedInRtl in_rtl;
SetJmp(cur_thread(), sp, mangled_sp); SetJmp(cur_thread(), sp, mangled_sp);
} }
@ -829,7 +816,6 @@ static void thread_finalize(void *v) {
return; return;
} }
{ {
ScopedInRtl in_rtl;
ThreadState *thr = cur_thread(); ThreadState *thr = cur_thread();
ThreadFinish(thr); ThreadFinish(thr);
SignalContext *sctx = thr->signal_ctx; SignalContext *sctx = thr->signal_ctx;
@ -854,7 +840,8 @@ extern "C" void *__tsan_thread_start_func(void *arg) {
int tid = 0; int tid = 0;
{ {
ThreadState *thr = cur_thread(); ThreadState *thr = cur_thread();
ScopedInRtl in_rtl; // Thread-local state is not initialized yet.
ScopedIgnoreInterceptors ignore;
if (pthread_setspecific(g_thread_finalize_key, if (pthread_setspecific(g_thread_finalize_key,
(void *)kPthreadDestructorIterations)) { (void *)kPthreadDestructorIterations)) {
Printf("ThreadSanitizer: failed to set thread key\n"); Printf("ThreadSanitizer: failed to set thread key\n");
@ -864,7 +851,6 @@ extern "C" void *__tsan_thread_start_func(void *arg) {
pthread_yield(); pthread_yield();
atomic_store(&p->tid, 0, memory_order_release); atomic_store(&p->tid, 0, memory_order_release);
ThreadStart(thr, tid, GetTid()); ThreadStart(thr, tid, GetTid());
CHECK_EQ(thr->in_rtl, 1);
} }
void *res = callback(param); void *res = callback(param);
// Prevent the callback from being tail called, // Prevent the callback from being tail called,
@ -890,7 +876,12 @@ TSAN_INTERCEPTOR(int, pthread_create,
p.callback = callback; p.callback = callback;
p.param = param; p.param = param;
atomic_store(&p.tid, 0, memory_order_relaxed); atomic_store(&p.tid, 0, memory_order_relaxed);
int res = REAL(pthread_create)(th, attr, __tsan_thread_start_func, &p); int res = -1;
{
// Otherwise we see false positives in pthread stack manipulation.
ScopedIgnoreInterceptors ignore;
res = REAL(pthread_create)(th, attr, __tsan_thread_start_func, &p);
}
if (res == 0) { if (res == 0) {
int tid = ThreadCreate(thr, pc, *(uptr*)th, detached); int tid = ThreadCreate(thr, pc, *(uptr*)th, detached);
CHECK_NE(tid, 0); CHECK_NE(tid, 0);
@ -1134,19 +1125,13 @@ TSAN_INTERCEPTOR(int, pthread_barrier_wait, void *b) {
TSAN_INTERCEPTOR(int, pthread_once, void *o, void (*f)()) { TSAN_INTERCEPTOR(int, pthread_once, void *o, void (*f)()) {
SCOPED_INTERCEPTOR_RAW(pthread_once, o, f); SCOPED_INTERCEPTOR_RAW(pthread_once, o, f);
// Using SCOPED_INTERCEPTOR_RAW, because if we are called from an ignored lib,
// the user callback must be executed with thr->in_rtl == 0.
if (o == 0 || f == 0) if (o == 0 || f == 0)
return EINVAL; return EINVAL;
atomic_uint32_t *a = static_cast<atomic_uint32_t*>(o); atomic_uint32_t *a = static_cast<atomic_uint32_t*>(o);
u32 v = atomic_load(a, memory_order_acquire); u32 v = atomic_load(a, memory_order_acquire);
if (v == 0 && atomic_compare_exchange_strong(a, &v, 1, if (v == 0 && atomic_compare_exchange_strong(a, &v, 1,
memory_order_relaxed)) { memory_order_relaxed)) {
const int old_in_rtl = thr->in_rtl;
thr->in_rtl = 0;
(*f)(); (*f)();
CHECK_EQ(thr->in_rtl, 0);
thr->in_rtl = old_in_rtl;
if (!thr->in_ignored_lib) if (!thr->in_ignored_lib)
Release(thr, pc, (uptr)o); Release(thr, pc, (uptr)o);
atomic_store(a, 2, memory_order_release); atomic_store(a, 2, memory_order_release);
@ -1640,9 +1625,7 @@ void ALWAYS_INLINE rtl_generic_sighandler(bool sigact, int sig,
// If we are in blocking function, we can safely process it now // If we are in blocking function, we can safely process it now
// (but check if we are in a recursive interceptor, // (but check if we are in a recursive interceptor,
// i.e. pthread_join()->munmap()). // i.e. pthread_join()->munmap()).
(sctx && sctx->in_blocking_func == 1 && thr->in_rtl == 1)) { (sctx && sctx->in_blocking_func == 1)) {
int in_rtl = thr->in_rtl;
thr->in_rtl = 0;
CHECK_EQ(thr->in_signal_handler, false); CHECK_EQ(thr->in_signal_handler, false);
thr->in_signal_handler = true; thr->in_signal_handler = true;
if (sigact) if (sigact)
@ -1651,7 +1634,6 @@ void ALWAYS_INLINE rtl_generic_sighandler(bool sigact, int sig,
sigactions[sig].sa_handler(sig); sigactions[sig].sa_handler(sig);
CHECK_EQ(thr->in_signal_handler, true); CHECK_EQ(thr->in_signal_handler, true);
thr->in_signal_handler = false; thr->in_signal_handler = false;
thr->in_rtl = in_rtl;
return; return;
} }
@ -1771,11 +1753,7 @@ TSAN_INTERCEPTOR(int, getaddrinfo, void *node, void *service,
// and can report false race between malloc and free // and can report false race between malloc and free
// inside of getaddrinfo. So ignore memory accesses. // inside of getaddrinfo. So ignore memory accesses.
ThreadIgnoreBegin(thr, pc); ThreadIgnoreBegin(thr, pc);
// getaddrinfo calls fopen, which can be intercepted by user.
thr->in_rtl--;
CHECK_EQ(thr->in_rtl, 0);
int res = REAL(getaddrinfo)(node, service, hints, rv); int res = REAL(getaddrinfo)(node, service, hints, rv);
thr->in_rtl++;
ThreadIgnoreEnd(thr, pc); ThreadIgnoreEnd(thr, pc);
return res; return res;
} }
@ -1843,14 +1821,8 @@ static void HandleRecvmsg(ThreadState *thr, uptr pc,
} }
#include "sanitizer_common/sanitizer_platform_interceptors.h" #include "sanitizer_common/sanitizer_platform_interceptors.h"
// Causes interceptor recursion (getpwuid_r() calls fopen())
#undef SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS
#undef SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS
// Causes interceptor recursion (getaddrinfo() and fopen()) // Causes interceptor recursion (getaddrinfo() and fopen())
#undef SANITIZER_INTERCEPT_GETADDRINFO #undef SANITIZER_INTERCEPT_GETADDRINFO
#undef SANITIZER_INTERCEPT_GETNAMEINFO
// Causes interceptor recursion (glob64() calls lstat64())
#undef SANITIZER_INTERCEPT_GLOB
#define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name) #define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name)
#define COMMON_INTERCEPTOR_UNPOISON_PARAM(ctx, count) \ #define COMMON_INTERCEPTOR_UNPOISON_PARAM(ctx, count) \
@ -1924,15 +1896,11 @@ struct ScopedSyscall {
explicit ScopedSyscall(ThreadState *thr) explicit ScopedSyscall(ThreadState *thr)
: thr(thr) { : thr(thr) {
if (thr->in_rtl == 0) Initialize(thr);
Initialize(thr);
thr->in_rtl++;
} }
~ScopedSyscall() { ~ScopedSyscall() {
thr->in_rtl--; ProcessPendingSignals(thr);
if (thr->in_rtl == 0)
ProcessPendingSignals(thr);
} }
}; };
@ -2035,7 +2003,6 @@ static void finalize(void *arg) {
} }
void ProcessPendingSignals(ThreadState *thr) { void ProcessPendingSignals(ThreadState *thr) {
CHECK_EQ(thr->in_rtl, 0);
SignalContext *sctx = SigCtx(thr); SignalContext *sctx = SigCtx(thr);
if (sctx == 0 || sctx->pending_signal_count == 0 || thr->in_signal_handler) if (sctx == 0 || sctx->pending_signal_count == 0 || thr->in_signal_handler)
return; return;
@ -2060,7 +2027,6 @@ void ProcessPendingSignals(ThreadState *thr) {
else else
sigactions[sig].sa_handler(sig); sigactions[sig].sa_handler(sig);
if (flags()->report_bugs && errno != 0) { if (flags()->report_bugs && errno != 0) {
ScopedInRtl in_rtl;
__tsan::StackTrace stack; __tsan::StackTrace stack;
uptr pc = signal->sigaction ? uptr pc = signal->sigaction ?
(uptr)sigactions[sig].sa_sigaction : (uptr)sigactions[sig].sa_sigaction :
@ -2089,8 +2055,6 @@ static void unreachable() {
} }
void InitializeInterceptors() { void InitializeInterceptors() {
CHECK_GT(cur_thread()->in_rtl, 0);
// We need to setup it early, because functions like dlsym() can call it. // We need to setup it early, because functions like dlsym() can call it.
REAL(memset) = internal_memset; REAL(memset) = internal_memset;
REAL(memcpy) = internal_memcpy; REAL(memcpy) = internal_memcpy;
@ -2283,8 +2247,7 @@ void InitializeInterceptors() {
} }
void internal_start_thread(void(*func)(void *arg), void *arg) { void internal_start_thread(void(*func)(void *arg), void *arg) {
// Start the thread with signals blocked, otherwise it can steal users // Start the thread with signals blocked, otherwise it can steal user signals.
// signals.
__sanitizer_kernel_sigset_t set, old; __sanitizer_kernel_sigset_t set, old;
internal_sigfillset(&set); internal_sigfillset(&set);
internal_sigprocmask(SIG_SETMASK, &set, &old); internal_sigprocmask(SIG_SETMASK, &set, &old);

View File

@ -33,22 +33,16 @@ class ScopedAnnotation {
public: public:
ScopedAnnotation(ThreadState *thr, const char *aname, const char *f, int l, ScopedAnnotation(ThreadState *thr, const char *aname, const char *f, int l,
uptr pc) uptr pc)
: thr_(thr) : thr_(thr) {
, in_rtl_(thr->in_rtl) {
CHECK_EQ(thr_->in_rtl, 0);
FuncEntry(thr_, pc); FuncEntry(thr_, pc);
thr_->in_rtl++;
DPrintf("#%d: annotation %s() %s:%d\n", thr_->tid, aname, f, l); DPrintf("#%d: annotation %s() %s:%d\n", thr_->tid, aname, f, l);
} }
~ScopedAnnotation() { ~ScopedAnnotation() {
thr_->in_rtl--;
CHECK_EQ(in_rtl_, thr_->in_rtl);
FuncExit(thr_); FuncExit(thr_);
} }
private: private:
ThreadState *const thr_; ThreadState *const thr_;
const int in_rtl_;
}; };
#define SCOPED_ANNOTATION(typ) \ #define SCOPED_ANNOTATION(typ) \

View File

@ -66,15 +66,11 @@ class ScopedAtomic {
ScopedAtomic(ThreadState *thr, uptr pc, const volatile void *a, ScopedAtomic(ThreadState *thr, uptr pc, const volatile void *a,
morder mo, const char *func) morder mo, const char *func)
: thr_(thr) { : thr_(thr) {
CHECK_EQ(thr_->in_rtl, 0);
ProcessPendingSignals(thr); ProcessPendingSignals(thr);
FuncEntry(thr_, pc); FuncEntry(thr_, pc);
DPrintf("#%d: %s(%p, %d)\n", thr_->tid, func, a, mo); DPrintf("#%d: %s(%p, %d)\n", thr_->tid, func, a, mo);
thr_->in_rtl++;
} }
~ScopedAtomic() { ~ScopedAtomic() {
thr_->in_rtl--;
CHECK_EQ(thr_->in_rtl, 0);
FuncExit(thr_); FuncExit(thr_);
} }
private: private:

View File

@ -79,13 +79,9 @@ class ScopedJavaFunc {
: thr_(thr) { : thr_(thr) {
Initialize(thr_); Initialize(thr_);
FuncEntry(thr, pc); FuncEntry(thr, pc);
CHECK_EQ(thr_->in_rtl, 0);
thr_->in_rtl++;
} }
~ScopedJavaFunc() { ~ScopedJavaFunc() {
thr_->in_rtl--;
CHECK_EQ(thr_->in_rtl, 0);
FuncExit(thr_); FuncExit(thr_);
// FIXME(dvyukov): process pending signals. // FIXME(dvyukov): process pending signals.
} }

View File

@ -102,7 +102,6 @@ static void SignalUnsafeCall(ThreadState *thr, uptr pc) {
} }
void *user_alloc(ThreadState *thr, uptr pc, uptr sz, uptr align) { void *user_alloc(ThreadState *thr, uptr pc, uptr sz, uptr align) {
CHECK_GT(thr->in_rtl, 0);
if ((sz >= (1ull << 40)) || (align >= (1ull << 40))) if ((sz >= (1ull << 40)) || (align >= (1ull << 40)))
return AllocatorReturnNull(); return AllocatorReturnNull();
void *p = allocator()->Allocate(&thr->alloc_cache, sz, align); void *p = allocator()->Allocate(&thr->alloc_cache, sz, align);
@ -122,7 +121,6 @@ void *user_alloc(ThreadState *thr, uptr pc, uptr sz, uptr align) {
} }
void user_free(ThreadState *thr, uptr pc, void *p) { void user_free(ThreadState *thr, uptr pc, void *p) {
CHECK_GT(thr->in_rtl, 0);
CHECK_NE(p, (void*)0); CHECK_NE(p, (void*)0);
DPrintf("#%d: free(%p)\n", thr->tid, p); DPrintf("#%d: free(%p)\n", thr->tid, p);
MBlock *b = (MBlock*)allocator()->GetMetaData(p); MBlock *b = (MBlock*)allocator()->GetMetaData(p);
@ -138,7 +136,7 @@ void user_free(ThreadState *thr, uptr pc, void *p) {
} }
b->ListReset(); b->ListReset();
} }
if (CTX() && CTX()->initialized && thr->in_rtl == 1) { if (CTX() && CTX()->initialized) {
if (thr->ignore_reads_and_writes == 0) if (thr->ignore_reads_and_writes == 0)
MemoryRangeFreed(thr, pc, (uptr)p, b->Size()); MemoryRangeFreed(thr, pc, (uptr)p, b->Size());
} }
@ -147,7 +145,6 @@ void user_free(ThreadState *thr, uptr pc, void *p) {
} }
void *user_realloc(ThreadState *thr, uptr pc, void *p, uptr sz) { void *user_realloc(ThreadState *thr, uptr pc, void *p, uptr sz) {
CHECK_GT(thr->in_rtl, 0);
void *p2 = 0; void *p2 = 0;
// FIXME: Handle "shrinking" more efficiently, // FIXME: Handle "shrinking" more efficiently,
// it seems that some software actually does this. // it seems that some software actually does this.
@ -167,7 +164,6 @@ void *user_realloc(ThreadState *thr, uptr pc, void *p, uptr sz) {
} }
uptr user_alloc_usable_size(ThreadState *thr, uptr pc, void *p) { uptr user_alloc_usable_size(ThreadState *thr, uptr pc, void *p) {
CHECK_GT(thr->in_rtl, 0);
if (p == 0) if (p == 0)
return 0; return 0;
MBlock *b = (MBlock*)allocator()->GetMetaData(p); MBlock *b = (MBlock*)allocator()->GetMetaData(p);
@ -186,7 +182,7 @@ MBlock *user_mblock(ThreadState *thr, void *p) {
void invoke_malloc_hook(void *ptr, uptr size) { void invoke_malloc_hook(void *ptr, uptr size) {
Context *ctx = CTX(); Context *ctx = CTX();
ThreadState *thr = cur_thread(); ThreadState *thr = cur_thread();
if (ctx == 0 || !ctx->initialized || thr->in_rtl) if (ctx == 0 || !ctx->initialized || thr->ignore_interceptors)
return; return;
__tsan_malloc_hook(ptr, size); __tsan_malloc_hook(ptr, size);
} }
@ -194,14 +190,13 @@ void invoke_malloc_hook(void *ptr, uptr size) {
void invoke_free_hook(void *ptr) { void invoke_free_hook(void *ptr) {
Context *ctx = CTX(); Context *ctx = CTX();
ThreadState *thr = cur_thread(); ThreadState *thr = cur_thread();
if (ctx == 0 || !ctx->initialized || thr->in_rtl) if (ctx == 0 || !ctx->initialized || thr->ignore_interceptors)
return; return;
__tsan_free_hook(ptr); __tsan_free_hook(ptr);
} }
void *internal_alloc(MBlockType typ, uptr sz) { void *internal_alloc(MBlockType typ, uptr sz) {
ThreadState *thr = cur_thread(); ThreadState *thr = cur_thread();
CHECK_GT(thr->in_rtl, 0);
CHECK_LE(sz, InternalSizeClassMap::kMaxSize); CHECK_LE(sz, InternalSizeClassMap::kMaxSize);
if (thr->nomalloc) { if (thr->nomalloc) {
thr->nomalloc = 0; // CHECK calls internal_malloc(). thr->nomalloc = 0; // CHECK calls internal_malloc().
@ -212,7 +207,6 @@ void *internal_alloc(MBlockType typ, uptr sz) {
void internal_free(void *p) { void internal_free(void *p) {
ThreadState *thr = cur_thread(); ThreadState *thr = cur_thread();
CHECK_GT(thr->in_rtl, 0);
if (thr->nomalloc) { if (thr->nomalloc) {
thr->nomalloc = 0; // CHECK calls internal_malloc(). thr->nomalloc = 0; // CHECK calls internal_malloc().
CHECK(0); CHECK(0);

View File

@ -38,6 +38,10 @@ class MutexSet {
uptr Size() const; uptr Size() const;
Desc Get(uptr i) const; Desc Get(uptr i) const;
void operator=(const MutexSet &other) {
internal_memcpy(this, &other, sizeof(*this));
}
private: private:
#ifndef TSAN_GO #ifndef TSAN_GO
uptr size_; uptr size_;
@ -45,6 +49,7 @@ class MutexSet {
#endif #endif
void RemovePos(uptr i); void RemovePos(uptr i);
MutexSet(const MutexSet&);
}; };
// Go does not have mutexes, so do not spend memory and time. // Go does not have mutexes, so do not spend memory and time.

View File

@ -61,27 +61,6 @@ namespace __tsan {
const uptr kPageSize = 4096; const uptr kPageSize = 4096;
#ifndef TSAN_GO
ScopedInRtl::ScopedInRtl()
: thr_(cur_thread()) {
in_rtl_ = thr_->in_rtl;
thr_->in_rtl++;
errno_ = errno;
}
ScopedInRtl::~ScopedInRtl() {
thr_->in_rtl--;
errno = errno_;
CHECK_EQ(in_rtl_, thr_->in_rtl);
}
#else
ScopedInRtl::ScopedInRtl() {
}
ScopedInRtl::~ScopedInRtl() {
}
#endif
void FillProfileCallback(uptr start, uptr rss, bool file, void FillProfileCallback(uptr start, uptr rss, bool file,
uptr *mem, uptr stats_size) { uptr *mem, uptr stats_size) {
CHECK_EQ(7, stats_size); CHECK_EQ(7, stats_size);
@ -135,7 +114,6 @@ void FlushShadowMemory() {
#ifndef TSAN_GO #ifndef TSAN_GO
static void ProtectRange(uptr beg, uptr end) { static void ProtectRange(uptr beg, uptr end) {
ScopedInRtl in_rtl;
CHECK_LE(beg, end); CHECK_LE(beg, end);
if (beg == end) if (beg == end)
return; return;

View File

@ -91,7 +91,7 @@ ThreadState::ThreadState(Context *ctx, int tid, int unique_id, u64 epoch,
// Do not touch these, rely on zero initialization, // Do not touch these, rely on zero initialization,
// they may be accessed before the ctor. // they may be accessed before the ctor.
// , ignore_reads_and_writes() // , ignore_reads_and_writes()
// , in_rtl() // , ignore_interceptors()
#ifndef TSAN_GO #ifndef TSAN_GO
, jmp_bufs(MBlockJmpBuf) , jmp_bufs(MBlockJmpBuf)
#endif #endif
@ -116,8 +116,9 @@ static void MemoryProfiler(Context *ctx, fd_t fd, int i) {
} }
static void BackgroundThread(void *arg) { static void BackgroundThread(void *arg) {
ScopedInRtl in_rtl;
Context *ctx = CTX(); Context *ctx = CTX();
// This is a non-initialized non-user thread, nothing to see here.
ScopedIgnoreInterceptors ignore;
const u64 kMs2Ns = 1000 * 1000; const u64 kMs2Ns = 1000 * 1000;
fd_t mprof_fd = kInvalidFd; fd_t mprof_fd = kInvalidFd;
@ -216,11 +217,12 @@ void Initialize(ThreadState *thr) {
if (is_initialized) if (is_initialized)
return; return;
is_initialized = true; is_initialized = true;
// We are not ready to handle interceptors yet.
ScopedIgnoreInterceptors ignore;
SanitizerToolName = "ThreadSanitizer"; SanitizerToolName = "ThreadSanitizer";
// Install tool-specific callbacks in sanitizer_common. // Install tool-specific callbacks in sanitizer_common.
SetCheckFailedCallback(TsanCheckFailed); SetCheckFailedCallback(TsanCheckFailed);
ScopedInRtl in_rtl;
#ifndef TSAN_GO #ifndef TSAN_GO
InitializeAllocator(); InitializeAllocator();
#endif #endif
@ -261,7 +263,6 @@ void Initialize(ThreadState *thr) {
int tid = ThreadCreate(thr, 0, 0, true); int tid = ThreadCreate(thr, 0, 0, true);
CHECK_EQ(tid, 0); CHECK_EQ(tid, 0);
ThreadStart(thr, tid, internal_getpid()); ThreadStart(thr, tid, internal_getpid());
CHECK_EQ(thr->in_rtl, 1);
ctx->initialized = true; ctx->initialized = true;
if (flags()->stop_on_start) { if (flags()->stop_on_start) {
@ -273,7 +274,6 @@ void Initialize(ThreadState *thr) {
} }
int Finalize(ThreadState *thr) { int Finalize(ThreadState *thr) {
ScopedInRtl in_rtl;
Context *ctx = __tsan::ctx; Context *ctx = __tsan::ctx;
bool failed = false; bool failed = false;
@ -340,7 +340,6 @@ u32 CurrentStackId(ThreadState *thr, uptr pc) {
void TraceSwitch(ThreadState *thr) { void TraceSwitch(ThreadState *thr) {
thr->nomalloc++; thr->nomalloc++;
ScopedInRtl in_rtl;
Trace *thr_trace = ThreadTrace(thr->tid); Trace *thr_trace = ThreadTrace(thr->tid);
Lock l(&thr_trace->mtx); Lock l(&thr_trace->mtx);
unsigned trace = (thr->fast_state.epoch() / kTracePartSize) % TraceParts(); unsigned trace = (thr->fast_state.epoch() / kTracePartSize) % TraceParts();
@ -657,7 +656,6 @@ void MemoryRangeImitateWrite(ThreadState *thr, uptr pc, uptr addr, uptr size) {
ALWAYS_INLINE USED ALWAYS_INLINE USED
void FuncEntry(ThreadState *thr, uptr pc) { void FuncEntry(ThreadState *thr, uptr pc) {
DCHECK_EQ(thr->in_rtl, 0);
StatInc(thr, StatFuncEnter); StatInc(thr, StatFuncEnter);
DPrintf2("#%d: FuncEntry %p\n", (int)thr->fast_state.tid(), (void*)pc); DPrintf2("#%d: FuncEntry %p\n", (int)thr->fast_state.tid(), (void*)pc);
thr->fast_state.IncrementEpoch(); thr->fast_state.IncrementEpoch();
@ -687,7 +685,6 @@ void FuncEntry(ThreadState *thr, uptr pc) {
ALWAYS_INLINE USED ALWAYS_INLINE USED
void FuncExit(ThreadState *thr) { void FuncExit(ThreadState *thr) {
DCHECK_EQ(thr->in_rtl, 0);
StatInc(thr, StatFuncExit); StatInc(thr, StatFuncExit);
DPrintf2("#%d: FuncExit\n", (int)thr->fast_state.tid()); DPrintf2("#%d: FuncExit\n", (int)thr->fast_state.tid());
thr->fast_state.IncrementEpoch(); thr->fast_state.IncrementEpoch();

View File

@ -433,11 +433,11 @@ struct ThreadState {
AllocatorCache alloc_cache; AllocatorCache alloc_cache;
InternalAllocatorCache internal_alloc_cache; InternalAllocatorCache internal_alloc_cache;
Vector<JmpBuf> jmp_bufs; Vector<JmpBuf> jmp_bufs;
int ignore_interceptors;
#endif #endif
u64 stat[StatCnt]; u64 stat[StatCnt];
const int tid; const int tid;
const int unique_id; const int unique_id;
int in_rtl;
bool in_symbolizer; bool in_symbolizer;
bool in_ignored_lib; bool in_ignored_lib;
bool is_alive; bool is_alive;
@ -551,14 +551,18 @@ struct Context {
u64 int_alloc_siz[MBlockTypeCount]; u64 int_alloc_siz[MBlockTypeCount];
}; };
class ScopedInRtl { struct ScopedIgnoreInterceptors {
public: ScopedIgnoreInterceptors() {
ScopedInRtl(); #ifndef TSAN_GO
~ScopedInRtl(); cur_thread()->ignore_interceptors++;
private: #endif
ThreadState*thr_; }
int in_rtl_;
int errno_; ~ScopedIgnoreInterceptors() {
#ifndef TSAN_GO
cur_thread()->ignore_interceptors--;
#endif
}
}; };
class ScopedReport { class ScopedReport {
@ -580,6 +584,9 @@ class ScopedReport {
private: private:
Context *ctx_; Context *ctx_;
ReportDesc *rep_; ReportDesc *rep_;
// Symbolizer makes lots of intercepted calls. If we try to process them,
// at best it will cause deadlocks on internal mutexes.
ScopedIgnoreInterceptors ignore_interceptors_;
void AddMutex(u64 id); void AddMutex(u64 id);

View File

@ -23,7 +23,6 @@ namespace __tsan {
void MutexCreate(ThreadState *thr, uptr pc, uptr addr, void MutexCreate(ThreadState *thr, uptr pc, uptr addr,
bool rw, bool recursive, bool linker_init) { bool rw, bool recursive, bool linker_init) {
Context *ctx = CTX(); Context *ctx = CTX();
CHECK_GT(thr->in_rtl, 0);
DPrintf("#%d: MutexCreate %zx\n", thr->tid, addr); DPrintf("#%d: MutexCreate %zx\n", thr->tid, addr);
StatInc(thr, StatMutexCreate); StatInc(thr, StatMutexCreate);
if (!linker_init && IsAppMem(addr)) { if (!linker_init && IsAppMem(addr)) {
@ -41,7 +40,6 @@ void MutexCreate(ThreadState *thr, uptr pc, uptr addr,
void MutexDestroy(ThreadState *thr, uptr pc, uptr addr) { void MutexDestroy(ThreadState *thr, uptr pc, uptr addr) {
Context *ctx = CTX(); Context *ctx = CTX();
CHECK_GT(thr->in_rtl, 0);
DPrintf("#%d: MutexDestroy %zx\n", thr->tid, addr); DPrintf("#%d: MutexDestroy %zx\n", thr->tid, addr);
StatInc(thr, StatMutexDestroy); StatInc(thr, StatMutexDestroy);
#ifndef TSAN_GO #ifndef TSAN_GO
@ -80,7 +78,6 @@ void MutexDestroy(ThreadState *thr, uptr pc, uptr addr) {
} }
void MutexLock(ThreadState *thr, uptr pc, uptr addr, int rec) { void MutexLock(ThreadState *thr, uptr pc, uptr addr, int rec) {
CHECK_GT(thr->in_rtl, 0);
DPrintf("#%d: MutexLock %zx rec=%d\n", thr->tid, addr, rec); DPrintf("#%d: MutexLock %zx rec=%d\n", thr->tid, addr, rec);
CHECK_GT(rec, 0); CHECK_GT(rec, 0);
if (IsAppMem(addr)) if (IsAppMem(addr))
@ -111,7 +108,6 @@ void MutexLock(ThreadState *thr, uptr pc, uptr addr, int rec) {
} }
int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, bool all) { int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, bool all) {
CHECK_GT(thr->in_rtl, 0);
DPrintf("#%d: MutexUnlock %zx all=%d\n", thr->tid, addr, all); DPrintf("#%d: MutexUnlock %zx all=%d\n", thr->tid, addr, all);
if (IsAppMem(addr)) if (IsAppMem(addr))
MemoryReadAtomic(thr, pc, addr, kSizeLog1); MemoryReadAtomic(thr, pc, addr, kSizeLog1);
@ -149,7 +145,6 @@ int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, bool all) {
} }
void MutexReadLock(ThreadState *thr, uptr pc, uptr addr) { void MutexReadLock(ThreadState *thr, uptr pc, uptr addr) {
CHECK_GT(thr->in_rtl, 0);
DPrintf("#%d: MutexReadLock %zx\n", thr->tid, addr); DPrintf("#%d: MutexReadLock %zx\n", thr->tid, addr);
StatInc(thr, StatMutexReadLock); StatInc(thr, StatMutexReadLock);
if (IsAppMem(addr)) if (IsAppMem(addr))
@ -169,7 +164,6 @@ void MutexReadLock(ThreadState *thr, uptr pc, uptr addr) {
} }
void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr) { void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr) {
CHECK_GT(thr->in_rtl, 0);
DPrintf("#%d: MutexReadUnlock %zx\n", thr->tid, addr); DPrintf("#%d: MutexReadUnlock %zx\n", thr->tid, addr);
StatInc(thr, StatMutexReadUnlock); StatInc(thr, StatMutexReadUnlock);
if (IsAppMem(addr)) if (IsAppMem(addr))
@ -188,7 +182,6 @@ void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr) {
} }
void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) { void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) {
CHECK_GT(thr->in_rtl, 0);
DPrintf("#%d: MutexReadOrWriteUnlock %zx\n", thr->tid, addr); DPrintf("#%d: MutexReadOrWriteUnlock %zx\n", thr->tid, addr);
if (IsAppMem(addr)) if (IsAppMem(addr))
MemoryReadAtomic(thr, pc, addr, kSizeLog1); MemoryReadAtomic(thr, pc, addr, kSizeLog1);
@ -226,7 +219,6 @@ void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) {
void MutexRepair(ThreadState *thr, uptr pc, uptr addr) { void MutexRepair(ThreadState *thr, uptr pc, uptr addr) {
Context *ctx = CTX(); Context *ctx = CTX();
CHECK_GT(thr->in_rtl, 0);
DPrintf("#%d: MutexRepair %zx\n", thr->tid, addr); DPrintf("#%d: MutexRepair %zx\n", thr->tid, addr);
SyncVar *s = ctx->synctab.GetOrCreateAndLock(thr, pc, addr, true); SyncVar *s = ctx->synctab.GetOrCreateAndLock(thr, pc, addr, true);
s->owner_tid = SyncVar::kInvalidTid; s->owner_tid = SyncVar::kInvalidTid;
@ -235,7 +227,6 @@ void MutexRepair(ThreadState *thr, uptr pc, uptr addr) {
} }
void Acquire(ThreadState *thr, uptr pc, uptr addr) { void Acquire(ThreadState *thr, uptr pc, uptr addr) {
CHECK_GT(thr->in_rtl, 0);
DPrintf("#%d: Acquire %zx\n", thr->tid, addr); DPrintf("#%d: Acquire %zx\n", thr->tid, addr);
if (thr->ignore_sync) if (thr->ignore_sync)
return; return;
@ -263,7 +254,6 @@ void AcquireGlobal(ThreadState *thr, uptr pc) {
} }
void Release(ThreadState *thr, uptr pc, uptr addr) { void Release(ThreadState *thr, uptr pc, uptr addr) {
CHECK_GT(thr->in_rtl, 0);
DPrintf("#%d: Release %zx\n", thr->tid, addr); DPrintf("#%d: Release %zx\n", thr->tid, addr);
if (thr->ignore_sync) if (thr->ignore_sync)
return; return;
@ -276,7 +266,6 @@ void Release(ThreadState *thr, uptr pc, uptr addr) {
} }
void ReleaseStore(ThreadState *thr, uptr pc, uptr addr) { void ReleaseStore(ThreadState *thr, uptr pc, uptr addr) {
CHECK_GT(thr->in_rtl, 0);
DPrintf("#%d: ReleaseStore %zx\n", thr->tid, addr); DPrintf("#%d: ReleaseStore %zx\n", thr->tid, addr);
if (thr->ignore_sync) if (thr->ignore_sync)
return; return;

View File

@ -34,7 +34,10 @@ static ReportStack *SymbolizeStack(const StackTrace& trace);
void TsanCheckFailed(const char *file, int line, const char *cond, void TsanCheckFailed(const char *file, int line, const char *cond,
u64 v1, u64 v2) { u64 v1, u64 v2) {
ScopedInRtl in_rtl; // There is high probability that interceptors will check-fail as well,
// on the other hand there is no sense in processing interceptors
// since we are going to die soon.
ScopedIgnoreInterceptors ignore;
Printf("FATAL: ThreadSanitizer CHECK failed: " Printf("FATAL: ThreadSanitizer CHECK failed: "
"%s:%d \"%s\" (0x%zx, 0x%zx)\n", "%s:%d \"%s\" (0x%zx, 0x%zx)\n",
file, line, cond, (uptr)v1, (uptr)v2); file, line, cond, (uptr)v1, (uptr)v2);
@ -605,10 +608,12 @@ static bool RaceBetweenAtomicAndFree(ThreadState *thr) {
} }
void ReportRace(ThreadState *thr) { void ReportRace(ThreadState *thr) {
// Symbolizer makes lots of intercepted calls. If we try to process them,
// at best it will cause deadlocks on internal mutexes.
ScopedIgnoreInterceptors ignore;
if (!flags()->report_bugs) if (!flags()->report_bugs)
return; return;
ScopedInRtl in_rtl;
if (!flags()->report_atomic_races && !RaceBetweenAtomicAndFree(thr)) if (!flags()->report_atomic_races && !RaceBetweenAtomicAndFree(thr))
return; return;

View File

@ -189,7 +189,6 @@ static void ThreadCheckIgnore(ThreadState *thr) {}
#endif #endif
void ThreadFinalize(ThreadState *thr) { void ThreadFinalize(ThreadState *thr) {
CHECK_GT(thr->in_rtl, 0);
ThreadCheckIgnore(thr); ThreadCheckIgnore(thr);
#ifndef TSAN_GO #ifndef TSAN_GO
if (!flags()->report_thread_leaks) if (!flags()->report_thread_leaks)
@ -208,7 +207,6 @@ void ThreadFinalize(ThreadState *thr) {
} }
int ThreadCount(ThreadState *thr) { int ThreadCount(ThreadState *thr) {
CHECK_GT(thr->in_rtl, 0);
Context *ctx = CTX(); Context *ctx = CTX();
uptr result; uptr result;
ctx->thread_registry->GetNumberOfThreads(0, 0, &result); ctx->thread_registry->GetNumberOfThreads(0, 0, &result);
@ -216,7 +214,6 @@ int ThreadCount(ThreadState *thr) {
} }
int ThreadCreate(ThreadState *thr, uptr pc, uptr uid, bool detached) { int ThreadCreate(ThreadState *thr, uptr pc, uptr uid, bool detached) {
CHECK_GT(thr->in_rtl, 0);
StatInc(thr, StatThreadCreate); StatInc(thr, StatThreadCreate);
Context *ctx = CTX(); Context *ctx = CTX();
OnCreatedArgs args = { thr, pc }; OnCreatedArgs args = { thr, pc };
@ -228,7 +225,6 @@ int ThreadCreate(ThreadState *thr, uptr pc, uptr uid, bool detached) {
void ThreadStart(ThreadState *thr, int tid, uptr os_id) { void ThreadStart(ThreadState *thr, int tid, uptr os_id) {
Context *ctx = CTX(); Context *ctx = CTX();
CHECK_GT(thr->in_rtl, 0);
uptr stk_addr = 0; uptr stk_addr = 0;
uptr stk_size = 0; uptr stk_size = 0;
uptr tls_addr = 0; uptr tls_addr = 0;
@ -264,7 +260,6 @@ void ThreadStart(ThreadState *thr, int tid, uptr os_id) {
} }
void ThreadFinish(ThreadState *thr) { void ThreadFinish(ThreadState *thr) {
CHECK_GT(thr->in_rtl, 0);
ThreadCheckIgnore(thr); ThreadCheckIgnore(thr);
StatInc(thr, StatThreadFinish); StatInc(thr, StatThreadFinish);
if (thr->stk_addr && thr->stk_size) if (thr->stk_addr && thr->stk_size)
@ -286,7 +281,6 @@ static bool FindThreadByUid(ThreadContextBase *tctx, void *arg) {
} }
int ThreadTid(ThreadState *thr, uptr pc, uptr uid) { int ThreadTid(ThreadState *thr, uptr pc, uptr uid) {
CHECK_GT(thr->in_rtl, 0);
Context *ctx = CTX(); Context *ctx = CTX();
int res = ctx->thread_registry->FindThread(FindThreadByUid, (void*)uid); int res = ctx->thread_registry->FindThread(FindThreadByUid, (void*)uid);
DPrintf("#%d: ThreadTid uid=%zu tid=%d\n", thr->tid, uid, res); DPrintf("#%d: ThreadTid uid=%zu tid=%d\n", thr->tid, uid, res);
@ -294,7 +288,6 @@ int ThreadTid(ThreadState *thr, uptr pc, uptr uid) {
} }
void ThreadJoin(ThreadState *thr, uptr pc, int tid) { void ThreadJoin(ThreadState *thr, uptr pc, int tid) {
CHECK_GT(thr->in_rtl, 0);
CHECK_GT(tid, 0); CHECK_GT(tid, 0);
CHECK_LT(tid, kMaxTid); CHECK_LT(tid, kMaxTid);
DPrintf("#%d: ThreadJoin tid=%d\n", thr->tid, tid); DPrintf("#%d: ThreadJoin tid=%d\n", thr->tid, tid);
@ -303,7 +296,6 @@ void ThreadJoin(ThreadState *thr, uptr pc, int tid) {
} }
void ThreadDetach(ThreadState *thr, uptr pc, int tid) { void ThreadDetach(ThreadState *thr, uptr pc, int tid) {
CHECK_GT(thr->in_rtl, 0);
CHECK_GT(tid, 0); CHECK_GT(tid, 0);
CHECK_LT(tid, kMaxTid); CHECK_LT(tid, kMaxTid);
Context *ctx = CTX(); Context *ctx = CTX();
@ -311,7 +303,6 @@ void ThreadDetach(ThreadState *thr, uptr pc, int tid) {
} }
void ThreadSetName(ThreadState *thr, const char *name) { void ThreadSetName(ThreadState *thr, const char *name) {
CHECK_GT(thr->in_rtl, 0);
CTX()->thread_registry->SetThreadName(thr->tid, name); CTX()->thread_registry->SetThreadName(thr->tid, name);
} }

View File

@ -58,10 +58,18 @@ class Vector {
return begin_[i]; return begin_[i];
} }
T *PushBack(T v = T()) { T *PushBack() {
EnsureSize(Size() + 1); EnsureSize(Size() + 1);
end_[-1] = v; T *p = &end_[-1];
return &end_[-1]; internal_memset(p, 0, sizeof(*p));
return p;
}
T *PushBack(const T& v) {
EnsureSize(Size() + 1);
T *p = &end_[-1];
internal_memcpy(p, &v, sizeof(*p));
return p;
} }
void PopBack() { void PopBack() {

View File

@ -17,7 +17,6 @@
namespace __tsan { namespace __tsan {
TEST(Clock, VectorBasic) { TEST(Clock, VectorBasic) {
ScopedInRtl in_rtl;
ThreadClock clk; ThreadClock clk;
CHECK_EQ(clk.size(), 0); CHECK_EQ(clk.size(), 0);
clk.tick(0); clk.tick(0);
@ -34,7 +33,6 @@ TEST(Clock, VectorBasic) {
} }
TEST(Clock, ChunkedBasic) { TEST(Clock, ChunkedBasic) {
ScopedInRtl in_rtl;
ThreadClock vector; ThreadClock vector;
SyncClock chunked; SyncClock chunked;
CHECK_EQ(vector.size(), 0); CHECK_EQ(vector.size(), 0);
@ -51,7 +49,6 @@ TEST(Clock, ChunkedBasic) {
} }
TEST(Clock, AcquireRelease) { TEST(Clock, AcquireRelease) {
ScopedInRtl in_rtl;
ThreadClock vector1; ThreadClock vector1;
vector1.tick(100); vector1.tick(100);
SyncClock chunked; SyncClock chunked;
@ -67,7 +64,6 @@ TEST(Clock, AcquireRelease) {
} }
TEST(Clock, ManyThreads) { TEST(Clock, ManyThreads) {
ScopedInRtl in_rtl;
SyncClock chunked; SyncClock chunked;
for (int i = 0; i < 100; i++) { for (int i = 0; i < 100; i++) {
ThreadClock vector; ThreadClock vector;
@ -85,7 +81,6 @@ TEST(Clock, ManyThreads) {
} }
TEST(Clock, DifferentSizes) { TEST(Clock, DifferentSizes) {
ScopedInRtl in_rtl;
{ {
ThreadClock vector1; ThreadClock vector1;
vector1.tick(10); vector1.tick(10);

View File

@ -18,7 +18,6 @@
namespace __tsan { namespace __tsan {
TEST(Flags, Basic) { TEST(Flags, Basic) {
ScopedInRtl in_rtl;
// At least should not crash. // At least should not crash.
Flags f; Flags f;
InitializeFlags(&f, 0); InitializeFlags(&f, 0);
@ -26,7 +25,6 @@ TEST(Flags, Basic) {
} }
TEST(Flags, DefaultValues) { TEST(Flags, DefaultValues) {
ScopedInRtl in_rtl;
Flags f; Flags f;
f.enable_annotations = false; f.enable_annotations = false;
@ -206,7 +204,6 @@ extern "C" const char *__tsan_default_options() {
} }
TEST(Flags, ParseDefaultOptions) { TEST(Flags, ParseDefaultOptions) {
ScopedInRtl in_rtl;
Flags f; Flags f;
test_default_options = options1; test_default_options = options1;
@ -219,7 +216,6 @@ TEST(Flags, ParseDefaultOptions) {
} }
TEST(Flags, ParseEnvOptions) { TEST(Flags, ParseEnvOptions) {
ScopedInRtl in_rtl;
Flags f; Flags f;
InitializeFlags(&f, options1); InitializeFlags(&f, options1);
@ -230,7 +226,6 @@ TEST(Flags, ParseEnvOptions) {
} }
TEST(Flags, ParsePriority) { TEST(Flags, ParsePriority) {
ScopedInRtl in_rtl;
Flags f; Flags f;
test_default_options = options2; test_default_options = options2;

View File

@ -28,7 +28,6 @@ uptr __tsan_get_allocated_size(void *p);
namespace __tsan { namespace __tsan {
TEST(Mman, Internal) { TEST(Mman, Internal) {
ScopedInRtl in_rtl;
char *p = (char*)internal_alloc(MBlockScopedBuf, 10); char *p = (char*)internal_alloc(MBlockScopedBuf, 10);
EXPECT_NE(p, (char*)0); EXPECT_NE(p, (char*)0);
char *p2 = (char*)internal_alloc(MBlockScopedBuf, 20); char *p2 = (char*)internal_alloc(MBlockScopedBuf, 20);
@ -45,7 +44,6 @@ TEST(Mman, Internal) {
} }
TEST(Mman, User) { TEST(Mman, User) {
ScopedInRtl in_rtl;
ThreadState *thr = cur_thread(); ThreadState *thr = cur_thread();
uptr pc = 0; uptr pc = 0;
char *p = (char*)user_alloc(thr, pc, 10); char *p = (char*)user_alloc(thr, pc, 10);
@ -72,7 +70,6 @@ TEST(Mman, User) {
} }
TEST(Mman, UserRealloc) { TEST(Mman, UserRealloc) {
ScopedInRtl in_rtl;
ThreadState *thr = cur_thread(); ThreadState *thr = cur_thread();
uptr pc = 0; uptr pc = 0;
{ {
@ -118,7 +115,6 @@ TEST(Mman, UserRealloc) {
} }
TEST(Mman, UsableSize) { TEST(Mman, UsableSize) {
ScopedInRtl in_rtl;
ThreadState *thr = cur_thread(); ThreadState *thr = cur_thread();
uptr pc = 0; uptr pc = 0;
char *p = (char*)user_alloc(thr, pc, 10); char *p = (char*)user_alloc(thr, pc, 10);
@ -131,7 +127,6 @@ TEST(Mman, UsableSize) {
} }
TEST(Mman, Stats) { TEST(Mman, Stats) {
ScopedInRtl in_rtl;
ThreadState *thr = cur_thread(); ThreadState *thr = cur_thread();
uptr alloc0 = __tsan_get_current_allocated_bytes(); uptr alloc0 = __tsan_get_current_allocated_bytes();

View File

@ -46,13 +46,11 @@ static void TestStackTrace(StackTrace *trace) {
} }
TEST(StackTrace, Basic) { TEST(StackTrace, Basic) {
ScopedInRtl in_rtl;
StackTrace trace; StackTrace trace;
TestStackTrace(&trace); TestStackTrace(&trace);
} }
TEST(StackTrace, StaticBasic) { TEST(StackTrace, StaticBasic) {
ScopedInRtl in_rtl;
uptr buf[10]; uptr buf[10];
StackTrace trace1(buf, 10); StackTrace trace1(buf, 10);
TestStackTrace(&trace1); TestStackTrace(&trace1);
@ -61,7 +59,6 @@ TEST(StackTrace, StaticBasic) {
} }
TEST(StackTrace, StaticTrim) { TEST(StackTrace, StaticTrim) {
ScopedInRtl in_rtl;
uptr buf[2]; uptr buf[2];
StackTrace trace(buf, 2); StackTrace trace(buf, 2);

View File

@ -25,7 +25,6 @@ TEST(Sync, Table) {
const uintptr_t kIters = 512*1024; const uintptr_t kIters = 512*1024;
const uintptr_t kRange = 10000; const uintptr_t kRange = 10000;
ScopedInRtl in_rtl;
ThreadState *thr = cur_thread(); ThreadState *thr = cur_thread();
uptr pc = 0; uptr pc = 0;

View File

@ -17,7 +17,6 @@
namespace __tsan { namespace __tsan {
TEST(Vector, Basic) { TEST(Vector, Basic) {
ScopedInRtl in_rtl;
Vector<int> v(MBlockScopedBuf); Vector<int> v(MBlockScopedBuf);
EXPECT_EQ(v.Size(), (uptr)0); EXPECT_EQ(v.Size(), (uptr)0);
v.PushBack(42); v.PushBack(42);
@ -30,7 +29,6 @@ TEST(Vector, Basic) {
} }
TEST(Vector, Stride) { TEST(Vector, Stride) {
ScopedInRtl in_rtl;
Vector<int> v(MBlockScopedBuf); Vector<int> v(MBlockScopedBuf);
for (int i = 0; i < 1000; i++) { for (int i = 0; i < 1000; i++) {
v.PushBack(i); v.PushBack(i);