forked from OSchip/llvm-project
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:
parent
27aea0b0b7
commit
ce3721057d
|
@ -70,12 +70,14 @@ presubmit:
|
|||
# Release build with clang.
|
||||
$(MAKE) -f Makefile.old clean
|
||||
$(MAKE) -f Makefile.old run DEBUG=0 -j 16 CC=$(CLANG) CXX=$(CLANG)++
|
||||
./check_memcpy.sh
|
||||
# Debug build with gcc
|
||||
$(MAKE) -f Makefile.old clean
|
||||
$(MAKE) -f Makefile.old run DEBUG=1 -j 16 CC=gcc CXX=g++
|
||||
# Release build with gcc
|
||||
$(MAKE) -f Makefile.old clean
|
||||
$(MAKE) -f Makefile.old run DEBUG=0 -j 16 CC=gcc CXX=g++
|
||||
./check_memcpy.sh
|
||||
./check_analyze.sh
|
||||
# Sanity check for Go runtime
|
||||
(cd go && ./buildgo.sh)
|
||||
|
|
|
@ -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
|
|
@ -88,17 +88,13 @@ static ThreadState *AllocGoroutine() {
|
|||
void __tsan_init(ThreadState **thrp) {
|
||||
ThreadState *thr = AllocGoroutine();
|
||||
main_thr = *thrp = thr;
|
||||
thr->in_rtl++;
|
||||
Initialize(thr);
|
||||
thr->in_rtl--;
|
||||
}
|
||||
|
||||
void __tsan_fini() {
|
||||
// FIXME: Not necessary thread 0.
|
||||
ThreadState *thr = main_thr;
|
||||
thr->in_rtl++;
|
||||
int res = Finalize(thr);
|
||||
thr->in_rtl--;
|
||||
exit(res);
|
||||
}
|
||||
|
||||
|
@ -137,9 +133,7 @@ void __tsan_func_exit(ThreadState *thr) {
|
|||
void __tsan_malloc(ThreadState *thr, void *p, uptr sz, void *pc) {
|
||||
if (thr == 0) // probably before __tsan_init()
|
||||
return;
|
||||
thr->in_rtl++;
|
||||
MemoryResetRange(thr, (uptr)pc, (uptr)p, sz);
|
||||
thr->in_rtl--;
|
||||
}
|
||||
|
||||
void __tsan_free(void *p) {
|
||||
|
@ -149,37 +143,25 @@ void __tsan_free(void *p) {
|
|||
void __tsan_go_start(ThreadState *parent, ThreadState **pthr, void *pc) {
|
||||
ThreadState *thr = AllocGoroutine();
|
||||
*pthr = thr;
|
||||
thr->in_rtl++;
|
||||
parent->in_rtl++;
|
||||
int goid = ThreadCreate(parent, (uptr)pc, 0, true);
|
||||
ThreadStart(thr, goid, 0);
|
||||
parent->in_rtl--;
|
||||
thr->in_rtl--;
|
||||
}
|
||||
|
||||
void __tsan_go_end(ThreadState *thr) {
|
||||
thr->in_rtl++;
|
||||
ThreadFinish(thr);
|
||||
thr->in_rtl--;
|
||||
internal_free(thr);
|
||||
}
|
||||
|
||||
void __tsan_acquire(ThreadState *thr, void *addr) {
|
||||
thr->in_rtl++;
|
||||
Acquire(thr, 0, (uptr)addr);
|
||||
thr->in_rtl--;
|
||||
}
|
||||
|
||||
void __tsan_release(ThreadState *thr, void *addr) {
|
||||
thr->in_rtl++;
|
||||
ReleaseStore(thr, 0, (uptr)addr);
|
||||
thr->in_rtl--;
|
||||
}
|
||||
|
||||
void __tsan_release_merge(ThreadState *thr, void *addr) {
|
||||
thr->in_rtl++;
|
||||
Release(thr, 0, (uptr)addr);
|
||||
thr->in_rtl--;
|
||||
}
|
||||
|
||||
void __tsan_finalizer_goroutine(ThreadState *thr) {
|
||||
|
|
|
@ -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
|
|
@ -144,7 +144,6 @@ void InitializeLibIgnore() {
|
|||
static SignalContext *SigCtx(ThreadState *thr) {
|
||||
SignalContext *ctx = (SignalContext*)thr->signal_ctx;
|
||||
if (ctx == 0 && thr->is_alive) {
|
||||
ScopedInRtl in_rtl;
|
||||
ctx = (SignalContext*)MmapOrDie(sizeof(*ctx), "SignalContext");
|
||||
MemoryResetRange(thr, (uptr)&SigCtx, (uptr)ctx, sizeof(*ctx));
|
||||
thr->signal_ctx = ctx;
|
||||
|
@ -161,7 +160,6 @@ class ScopedInterceptor {
|
|||
private:
|
||||
ThreadState *const thr_;
|
||||
const uptr pc_;
|
||||
const int in_rtl_;
|
||||
bool in_ignored_lib_;
|
||||
};
|
||||
|
||||
|
@ -169,16 +167,12 @@ ScopedInterceptor::ScopedInterceptor(ThreadState *thr, const char *fname,
|
|||
uptr pc)
|
||||
: thr_(thr)
|
||||
, pc_(pc)
|
||||
, in_rtl_(thr->in_rtl)
|
||||
, in_ignored_lib_(false) {
|
||||
if (thr_->in_rtl == 0) {
|
||||
if (!thr_->ignore_interceptors) {
|
||||
Initialize(thr);
|
||||
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)) {
|
||||
in_ignored_lib_ = true;
|
||||
thr_->in_ignored_lib = true;
|
||||
|
@ -191,12 +185,10 @@ ScopedInterceptor::~ScopedInterceptor() {
|
|||
thr_->in_ignored_lib = false;
|
||||
ThreadIgnoreEnd(thr_, pc_);
|
||||
}
|
||||
thr_->in_rtl--;
|
||||
if (thr_->in_rtl == 0) {
|
||||
if (!thr_->ignore_interceptors) {
|
||||
FuncExit(thr_);
|
||||
ProcessPendingSignals(thr_);
|
||||
}
|
||||
CHECK_EQ(in_rtl_, thr_->in_rtl);
|
||||
}
|
||||
|
||||
#define SCOPED_INTERCEPTOR_RAW(func, ...) \
|
||||
|
@ -215,7 +207,7 @@ ScopedInterceptor::~ScopedInterceptor() {
|
|||
Printf("FATAL: ThreadSanitizer: failed to intercept %s\n", #func); \
|
||||
Die(); \
|
||||
} \
|
||||
if (thr->in_rtl > 1 || thr->in_ignored_lib) \
|
||||
if (thr->ignore_interceptors || thr->in_ignored_lib) \
|
||||
return REAL(func)(__VA_ARGS__); \
|
||||
/**/
|
||||
|
||||
|
@ -235,6 +227,13 @@ struct BlockingCall {
|
|||
}
|
||||
|
||||
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) {
|
||||
|
@ -260,22 +259,14 @@ TSAN_INTERCEPTOR(int, nanosleep, void *req, void *rem) {
|
|||
|
||||
TSAN_INTERCEPTOR(void*, dlopen, const char *filename, int flag) {
|
||||
SCOPED_INTERCEPTOR_RAW(dlopen, filename, flag);
|
||||
// dlopen will execute global constructors, so it must be not in rtl.
|
||||
CHECK_EQ(thr->in_rtl, 1);
|
||||
thr->in_rtl = 0;
|
||||
void *res = REAL(dlopen)(filename, flag);
|
||||
thr->in_rtl = 1;
|
||||
libignore()->OnLibraryLoaded(filename);
|
||||
return res;
|
||||
}
|
||||
|
||||
TSAN_INTERCEPTOR(int, dlclose, void *handle) {
|
||||
SCOPED_INTERCEPTOR_RAW(dlclose, handle);
|
||||
// dlclose will execute global destructors, so it must be not in rtl.
|
||||
CHECK_EQ(thr->in_rtl, 1);
|
||||
thr->in_rtl = 0;
|
||||
int res = REAL(dlclose)(handle);
|
||||
thr->in_rtl = 1;
|
||||
libignore()->OnLibraryUnloaded();
|
||||
return res;
|
||||
}
|
||||
|
@ -303,7 +294,6 @@ class AtExitContext {
|
|||
}
|
||||
|
||||
void exit(ThreadState *thr, uptr pc) {
|
||||
CHECK_EQ(thr->in_rtl, 0);
|
||||
for (;;) {
|
||||
atexit_t f = 0;
|
||||
void *arg = 0;
|
||||
|
@ -315,14 +305,12 @@ class AtExitContext {
|
|||
f = stack_[pos_];
|
||||
arg = args_[pos_];
|
||||
is_on_exit = is_on_exits_[pos_];
|
||||
ScopedInRtl in_rtl;
|
||||
Acquire(thr, pc, (uptr)this);
|
||||
}
|
||||
}
|
||||
if (f == 0)
|
||||
break;
|
||||
DPrintf("#%d: executing atexit func %p\n", thr->tid, f);
|
||||
CHECK_EQ(thr->in_rtl, 0);
|
||||
if (is_on_exit)
|
||||
((void(*)(int status, void *arg))f)(0, arg);
|
||||
else
|
||||
|
@ -415,7 +403,6 @@ static void LongJmp(ThreadState *thr, uptr *env) {
|
|||
|
||||
// FIXME: put everything below into a common extern "C" block?
|
||||
extern "C" void __tsan_setjmp(uptr sp, uptr mangled_sp) {
|
||||
ScopedInRtl in_rtl;
|
||||
SetJmp(cur_thread(), sp, mangled_sp);
|
||||
}
|
||||
|
||||
|
@ -829,7 +816,6 @@ static void thread_finalize(void *v) {
|
|||
return;
|
||||
}
|
||||
{
|
||||
ScopedInRtl in_rtl;
|
||||
ThreadState *thr = cur_thread();
|
||||
ThreadFinish(thr);
|
||||
SignalContext *sctx = thr->signal_ctx;
|
||||
|
@ -854,7 +840,8 @@ extern "C" void *__tsan_thread_start_func(void *arg) {
|
|||
int tid = 0;
|
||||
{
|
||||
ThreadState *thr = cur_thread();
|
||||
ScopedInRtl in_rtl;
|
||||
// Thread-local state is not initialized yet.
|
||||
ScopedIgnoreInterceptors ignore;
|
||||
if (pthread_setspecific(g_thread_finalize_key,
|
||||
(void *)kPthreadDestructorIterations)) {
|
||||
Printf("ThreadSanitizer: failed to set thread key\n");
|
||||
|
@ -864,7 +851,6 @@ extern "C" void *__tsan_thread_start_func(void *arg) {
|
|||
pthread_yield();
|
||||
atomic_store(&p->tid, 0, memory_order_release);
|
||||
ThreadStart(thr, tid, GetTid());
|
||||
CHECK_EQ(thr->in_rtl, 1);
|
||||
}
|
||||
void *res = callback(param);
|
||||
// Prevent the callback from being tail called,
|
||||
|
@ -890,7 +876,12 @@ TSAN_INTERCEPTOR(int, pthread_create,
|
|||
p.callback = callback;
|
||||
p.param = param;
|
||||
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) {
|
||||
int tid = ThreadCreate(thr, pc, *(uptr*)th, detached);
|
||||
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)()) {
|
||||
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)
|
||||
return EINVAL;
|
||||
atomic_uint32_t *a = static_cast<atomic_uint32_t*>(o);
|
||||
u32 v = atomic_load(a, memory_order_acquire);
|
||||
if (v == 0 && atomic_compare_exchange_strong(a, &v, 1,
|
||||
memory_order_relaxed)) {
|
||||
const int old_in_rtl = thr->in_rtl;
|
||||
thr->in_rtl = 0;
|
||||
(*f)();
|
||||
CHECK_EQ(thr->in_rtl, 0);
|
||||
thr->in_rtl = old_in_rtl;
|
||||
if (!thr->in_ignored_lib)
|
||||
Release(thr, pc, (uptr)o);
|
||||
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
|
||||
// (but check if we are in a recursive interceptor,
|
||||
// i.e. pthread_join()->munmap()).
|
||||
(sctx && sctx->in_blocking_func == 1 && thr->in_rtl == 1)) {
|
||||
int in_rtl = thr->in_rtl;
|
||||
thr->in_rtl = 0;
|
||||
(sctx && sctx->in_blocking_func == 1)) {
|
||||
CHECK_EQ(thr->in_signal_handler, false);
|
||||
thr->in_signal_handler = true;
|
||||
if (sigact)
|
||||
|
@ -1651,7 +1634,6 @@ void ALWAYS_INLINE rtl_generic_sighandler(bool sigact, int sig,
|
|||
sigactions[sig].sa_handler(sig);
|
||||
CHECK_EQ(thr->in_signal_handler, true);
|
||||
thr->in_signal_handler = false;
|
||||
thr->in_rtl = in_rtl;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1771,11 +1753,7 @@ TSAN_INTERCEPTOR(int, getaddrinfo, void *node, void *service,
|
|||
// and can report false race between malloc and free
|
||||
// inside of getaddrinfo. So ignore memory accesses.
|
||||
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);
|
||||
thr->in_rtl++;
|
||||
ThreadIgnoreEnd(thr, pc);
|
||||
return res;
|
||||
}
|
||||
|
@ -1843,14 +1821,8 @@ static void HandleRecvmsg(ThreadState *thr, uptr pc,
|
|||
}
|
||||
|
||||
#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())
|
||||
#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_INTERCEPTOR_UNPOISON_PARAM(ctx, count) \
|
||||
|
@ -1924,15 +1896,11 @@ struct ScopedSyscall {
|
|||
|
||||
explicit ScopedSyscall(ThreadState *thr)
|
||||
: thr(thr) {
|
||||
if (thr->in_rtl == 0)
|
||||
Initialize(thr);
|
||||
thr->in_rtl++;
|
||||
Initialize(thr);
|
||||
}
|
||||
|
||||
~ScopedSyscall() {
|
||||
thr->in_rtl--;
|
||||
if (thr->in_rtl == 0)
|
||||
ProcessPendingSignals(thr);
|
||||
ProcessPendingSignals(thr);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -2035,7 +2003,6 @@ static void finalize(void *arg) {
|
|||
}
|
||||
|
||||
void ProcessPendingSignals(ThreadState *thr) {
|
||||
CHECK_EQ(thr->in_rtl, 0);
|
||||
SignalContext *sctx = SigCtx(thr);
|
||||
if (sctx == 0 || sctx->pending_signal_count == 0 || thr->in_signal_handler)
|
||||
return;
|
||||
|
@ -2060,7 +2027,6 @@ void ProcessPendingSignals(ThreadState *thr) {
|
|||
else
|
||||
sigactions[sig].sa_handler(sig);
|
||||
if (flags()->report_bugs && errno != 0) {
|
||||
ScopedInRtl in_rtl;
|
||||
__tsan::StackTrace stack;
|
||||
uptr pc = signal->sigaction ?
|
||||
(uptr)sigactions[sig].sa_sigaction :
|
||||
|
@ -2089,8 +2055,6 @@ static void unreachable() {
|
|||
}
|
||||
|
||||
void InitializeInterceptors() {
|
||||
CHECK_GT(cur_thread()->in_rtl, 0);
|
||||
|
||||
// We need to setup it early, because functions like dlsym() can call it.
|
||||
REAL(memset) = internal_memset;
|
||||
REAL(memcpy) = internal_memcpy;
|
||||
|
@ -2283,8 +2247,7 @@ void InitializeInterceptors() {
|
|||
}
|
||||
|
||||
void internal_start_thread(void(*func)(void *arg), void *arg) {
|
||||
// Start the thread with signals blocked, otherwise it can steal users
|
||||
// signals.
|
||||
// Start the thread with signals blocked, otherwise it can steal user signals.
|
||||
__sanitizer_kernel_sigset_t set, old;
|
||||
internal_sigfillset(&set);
|
||||
internal_sigprocmask(SIG_SETMASK, &set, &old);
|
||||
|
|
|
@ -33,22 +33,16 @@ class ScopedAnnotation {
|
|||
public:
|
||||
ScopedAnnotation(ThreadState *thr, const char *aname, const char *f, int l,
|
||||
uptr pc)
|
||||
: thr_(thr)
|
||||
, in_rtl_(thr->in_rtl) {
|
||||
CHECK_EQ(thr_->in_rtl, 0);
|
||||
: thr_(thr) {
|
||||
FuncEntry(thr_, pc);
|
||||
thr_->in_rtl++;
|
||||
DPrintf("#%d: annotation %s() %s:%d\n", thr_->tid, aname, f, l);
|
||||
}
|
||||
|
||||
~ScopedAnnotation() {
|
||||
thr_->in_rtl--;
|
||||
CHECK_EQ(in_rtl_, thr_->in_rtl);
|
||||
FuncExit(thr_);
|
||||
}
|
||||
private:
|
||||
ThreadState *const thr_;
|
||||
const int in_rtl_;
|
||||
};
|
||||
|
||||
#define SCOPED_ANNOTATION(typ) \
|
||||
|
|
|
@ -66,15 +66,11 @@ class ScopedAtomic {
|
|||
ScopedAtomic(ThreadState *thr, uptr pc, const volatile void *a,
|
||||
morder mo, const char *func)
|
||||
: thr_(thr) {
|
||||
CHECK_EQ(thr_->in_rtl, 0);
|
||||
ProcessPendingSignals(thr);
|
||||
FuncEntry(thr_, pc);
|
||||
DPrintf("#%d: %s(%p, %d)\n", thr_->tid, func, a, mo);
|
||||
thr_->in_rtl++;
|
||||
}
|
||||
~ScopedAtomic() {
|
||||
thr_->in_rtl--;
|
||||
CHECK_EQ(thr_->in_rtl, 0);
|
||||
FuncExit(thr_);
|
||||
}
|
||||
private:
|
||||
|
|
|
@ -79,13 +79,9 @@ class ScopedJavaFunc {
|
|||
: thr_(thr) {
|
||||
Initialize(thr_);
|
||||
FuncEntry(thr, pc);
|
||||
CHECK_EQ(thr_->in_rtl, 0);
|
||||
thr_->in_rtl++;
|
||||
}
|
||||
|
||||
~ScopedJavaFunc() {
|
||||
thr_->in_rtl--;
|
||||
CHECK_EQ(thr_->in_rtl, 0);
|
||||
FuncExit(thr_);
|
||||
// FIXME(dvyukov): process pending signals.
|
||||
}
|
||||
|
|
|
@ -102,7 +102,6 @@ static void SignalUnsafeCall(ThreadState *thr, uptr pc) {
|
|||
}
|
||||
|
||||
void *user_alloc(ThreadState *thr, uptr pc, uptr sz, uptr align) {
|
||||
CHECK_GT(thr->in_rtl, 0);
|
||||
if ((sz >= (1ull << 40)) || (align >= (1ull << 40)))
|
||||
return AllocatorReturnNull();
|
||||
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) {
|
||||
CHECK_GT(thr->in_rtl, 0);
|
||||
CHECK_NE(p, (void*)0);
|
||||
DPrintf("#%d: free(%p)\n", thr->tid, p);
|
||||
MBlock *b = (MBlock*)allocator()->GetMetaData(p);
|
||||
|
@ -138,7 +136,7 @@ void user_free(ThreadState *thr, uptr pc, void *p) {
|
|||
}
|
||||
b->ListReset();
|
||||
}
|
||||
if (CTX() && CTX()->initialized && thr->in_rtl == 1) {
|
||||
if (CTX() && CTX()->initialized) {
|
||||
if (thr->ignore_reads_and_writes == 0)
|
||||
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) {
|
||||
CHECK_GT(thr->in_rtl, 0);
|
||||
void *p2 = 0;
|
||||
// FIXME: Handle "shrinking" more efficiently,
|
||||
// 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) {
|
||||
CHECK_GT(thr->in_rtl, 0);
|
||||
if (p == 0)
|
||||
return 0;
|
||||
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) {
|
||||
Context *ctx = CTX();
|
||||
ThreadState *thr = cur_thread();
|
||||
if (ctx == 0 || !ctx->initialized || thr->in_rtl)
|
||||
if (ctx == 0 || !ctx->initialized || thr->ignore_interceptors)
|
||||
return;
|
||||
__tsan_malloc_hook(ptr, size);
|
||||
}
|
||||
|
@ -194,14 +190,13 @@ void invoke_malloc_hook(void *ptr, uptr size) {
|
|||
void invoke_free_hook(void *ptr) {
|
||||
Context *ctx = CTX();
|
||||
ThreadState *thr = cur_thread();
|
||||
if (ctx == 0 || !ctx->initialized || thr->in_rtl)
|
||||
if (ctx == 0 || !ctx->initialized || thr->ignore_interceptors)
|
||||
return;
|
||||
__tsan_free_hook(ptr);
|
||||
}
|
||||
|
||||
void *internal_alloc(MBlockType typ, uptr sz) {
|
||||
ThreadState *thr = cur_thread();
|
||||
CHECK_GT(thr->in_rtl, 0);
|
||||
CHECK_LE(sz, InternalSizeClassMap::kMaxSize);
|
||||
if (thr->nomalloc) {
|
||||
thr->nomalloc = 0; // CHECK calls internal_malloc().
|
||||
|
@ -212,7 +207,6 @@ void *internal_alloc(MBlockType typ, uptr sz) {
|
|||
|
||||
void internal_free(void *p) {
|
||||
ThreadState *thr = cur_thread();
|
||||
CHECK_GT(thr->in_rtl, 0);
|
||||
if (thr->nomalloc) {
|
||||
thr->nomalloc = 0; // CHECK calls internal_malloc().
|
||||
CHECK(0);
|
||||
|
|
|
@ -38,6 +38,10 @@ class MutexSet {
|
|||
uptr Size() const;
|
||||
Desc Get(uptr i) const;
|
||||
|
||||
void operator=(const MutexSet &other) {
|
||||
internal_memcpy(this, &other, sizeof(*this));
|
||||
}
|
||||
|
||||
private:
|
||||
#ifndef TSAN_GO
|
||||
uptr size_;
|
||||
|
@ -45,6 +49,7 @@ class MutexSet {
|
|||
#endif
|
||||
|
||||
void RemovePos(uptr i);
|
||||
MutexSet(const MutexSet&);
|
||||
};
|
||||
|
||||
// Go does not have mutexes, so do not spend memory and time.
|
||||
|
|
|
@ -61,27 +61,6 @@ namespace __tsan {
|
|||
|
||||
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,
|
||||
uptr *mem, uptr stats_size) {
|
||||
CHECK_EQ(7, stats_size);
|
||||
|
@ -135,7 +114,6 @@ void FlushShadowMemory() {
|
|||
|
||||
#ifndef TSAN_GO
|
||||
static void ProtectRange(uptr beg, uptr end) {
|
||||
ScopedInRtl in_rtl;
|
||||
CHECK_LE(beg, end);
|
||||
if (beg == end)
|
||||
return;
|
||||
|
|
|
@ -91,7 +91,7 @@ ThreadState::ThreadState(Context *ctx, int tid, int unique_id, u64 epoch,
|
|||
// Do not touch these, rely on zero initialization,
|
||||
// they may be accessed before the ctor.
|
||||
// , ignore_reads_and_writes()
|
||||
// , in_rtl()
|
||||
// , ignore_interceptors()
|
||||
#ifndef TSAN_GO
|
||||
, jmp_bufs(MBlockJmpBuf)
|
||||
#endif
|
||||
|
@ -116,8 +116,9 @@ static void MemoryProfiler(Context *ctx, fd_t fd, int i) {
|
|||
}
|
||||
|
||||
static void BackgroundThread(void *arg) {
|
||||
ScopedInRtl in_rtl;
|
||||
Context *ctx = CTX();
|
||||
// This is a non-initialized non-user thread, nothing to see here.
|
||||
ScopedIgnoreInterceptors ignore;
|
||||
const u64 kMs2Ns = 1000 * 1000;
|
||||
|
||||
fd_t mprof_fd = kInvalidFd;
|
||||
|
@ -216,11 +217,12 @@ void Initialize(ThreadState *thr) {
|
|||
if (is_initialized)
|
||||
return;
|
||||
is_initialized = true;
|
||||
// We are not ready to handle interceptors yet.
|
||||
ScopedIgnoreInterceptors ignore;
|
||||
SanitizerToolName = "ThreadSanitizer";
|
||||
// Install tool-specific callbacks in sanitizer_common.
|
||||
SetCheckFailedCallback(TsanCheckFailed);
|
||||
|
||||
ScopedInRtl in_rtl;
|
||||
#ifndef TSAN_GO
|
||||
InitializeAllocator();
|
||||
#endif
|
||||
|
@ -261,7 +263,6 @@ void Initialize(ThreadState *thr) {
|
|||
int tid = ThreadCreate(thr, 0, 0, true);
|
||||
CHECK_EQ(tid, 0);
|
||||
ThreadStart(thr, tid, internal_getpid());
|
||||
CHECK_EQ(thr->in_rtl, 1);
|
||||
ctx->initialized = true;
|
||||
|
||||
if (flags()->stop_on_start) {
|
||||
|
@ -273,7 +274,6 @@ void Initialize(ThreadState *thr) {
|
|||
}
|
||||
|
||||
int Finalize(ThreadState *thr) {
|
||||
ScopedInRtl in_rtl;
|
||||
Context *ctx = __tsan::ctx;
|
||||
bool failed = false;
|
||||
|
||||
|
@ -340,7 +340,6 @@ u32 CurrentStackId(ThreadState *thr, uptr pc) {
|
|||
|
||||
void TraceSwitch(ThreadState *thr) {
|
||||
thr->nomalloc++;
|
||||
ScopedInRtl in_rtl;
|
||||
Trace *thr_trace = ThreadTrace(thr->tid);
|
||||
Lock l(&thr_trace->mtx);
|
||||
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
|
||||
void FuncEntry(ThreadState *thr, uptr pc) {
|
||||
DCHECK_EQ(thr->in_rtl, 0);
|
||||
StatInc(thr, StatFuncEnter);
|
||||
DPrintf2("#%d: FuncEntry %p\n", (int)thr->fast_state.tid(), (void*)pc);
|
||||
thr->fast_state.IncrementEpoch();
|
||||
|
@ -687,7 +685,6 @@ void FuncEntry(ThreadState *thr, uptr pc) {
|
|||
|
||||
ALWAYS_INLINE USED
|
||||
void FuncExit(ThreadState *thr) {
|
||||
DCHECK_EQ(thr->in_rtl, 0);
|
||||
StatInc(thr, StatFuncExit);
|
||||
DPrintf2("#%d: FuncExit\n", (int)thr->fast_state.tid());
|
||||
thr->fast_state.IncrementEpoch();
|
||||
|
|
|
@ -433,11 +433,11 @@ struct ThreadState {
|
|||
AllocatorCache alloc_cache;
|
||||
InternalAllocatorCache internal_alloc_cache;
|
||||
Vector<JmpBuf> jmp_bufs;
|
||||
int ignore_interceptors;
|
||||
#endif
|
||||
u64 stat[StatCnt];
|
||||
const int tid;
|
||||
const int unique_id;
|
||||
int in_rtl;
|
||||
bool in_symbolizer;
|
||||
bool in_ignored_lib;
|
||||
bool is_alive;
|
||||
|
@ -551,14 +551,18 @@ struct Context {
|
|||
u64 int_alloc_siz[MBlockTypeCount];
|
||||
};
|
||||
|
||||
class ScopedInRtl {
|
||||
public:
|
||||
ScopedInRtl();
|
||||
~ScopedInRtl();
|
||||
private:
|
||||
ThreadState*thr_;
|
||||
int in_rtl_;
|
||||
int errno_;
|
||||
struct ScopedIgnoreInterceptors {
|
||||
ScopedIgnoreInterceptors() {
|
||||
#ifndef TSAN_GO
|
||||
cur_thread()->ignore_interceptors++;
|
||||
#endif
|
||||
}
|
||||
|
||||
~ScopedIgnoreInterceptors() {
|
||||
#ifndef TSAN_GO
|
||||
cur_thread()->ignore_interceptors--;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
class ScopedReport {
|
||||
|
@ -580,6 +584,9 @@ class ScopedReport {
|
|||
private:
|
||||
Context *ctx_;
|
||||
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);
|
||||
|
||||
|
|
|
@ -23,7 +23,6 @@ namespace __tsan {
|
|||
void MutexCreate(ThreadState *thr, uptr pc, uptr addr,
|
||||
bool rw, bool recursive, bool linker_init) {
|
||||
Context *ctx = CTX();
|
||||
CHECK_GT(thr->in_rtl, 0);
|
||||
DPrintf("#%d: MutexCreate %zx\n", thr->tid, addr);
|
||||
StatInc(thr, StatMutexCreate);
|
||||
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) {
|
||||
Context *ctx = CTX();
|
||||
CHECK_GT(thr->in_rtl, 0);
|
||||
DPrintf("#%d: MutexDestroy %zx\n", thr->tid, addr);
|
||||
StatInc(thr, StatMutexDestroy);
|
||||
#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) {
|
||||
CHECK_GT(thr->in_rtl, 0);
|
||||
DPrintf("#%d: MutexLock %zx rec=%d\n", thr->tid, addr, rec);
|
||||
CHECK_GT(rec, 0);
|
||||
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) {
|
||||
CHECK_GT(thr->in_rtl, 0);
|
||||
DPrintf("#%d: MutexUnlock %zx all=%d\n", thr->tid, addr, all);
|
||||
if (IsAppMem(addr))
|
||||
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) {
|
||||
CHECK_GT(thr->in_rtl, 0);
|
||||
DPrintf("#%d: MutexReadLock %zx\n", thr->tid, addr);
|
||||
StatInc(thr, StatMutexReadLock);
|
||||
if (IsAppMem(addr))
|
||||
|
@ -169,7 +164,6 @@ void MutexReadLock(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);
|
||||
StatInc(thr, StatMutexReadUnlock);
|
||||
if (IsAppMem(addr))
|
||||
|
@ -188,7 +182,6 @@ void MutexReadUnlock(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);
|
||||
if (IsAppMem(addr))
|
||||
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) {
|
||||
Context *ctx = CTX();
|
||||
CHECK_GT(thr->in_rtl, 0);
|
||||
DPrintf("#%d: MutexRepair %zx\n", thr->tid, addr);
|
||||
SyncVar *s = ctx->synctab.GetOrCreateAndLock(thr, pc, addr, true);
|
||||
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) {
|
||||
CHECK_GT(thr->in_rtl, 0);
|
||||
DPrintf("#%d: Acquire %zx\n", thr->tid, addr);
|
||||
if (thr->ignore_sync)
|
||||
return;
|
||||
|
@ -263,7 +254,6 @@ void AcquireGlobal(ThreadState *thr, uptr pc) {
|
|||
}
|
||||
|
||||
void Release(ThreadState *thr, uptr pc, uptr addr) {
|
||||
CHECK_GT(thr->in_rtl, 0);
|
||||
DPrintf("#%d: Release %zx\n", thr->tid, addr);
|
||||
if (thr->ignore_sync)
|
||||
return;
|
||||
|
@ -276,7 +266,6 @@ void Release(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);
|
||||
if (thr->ignore_sync)
|
||||
return;
|
||||
|
|
|
@ -34,7 +34,10 @@ static ReportStack *SymbolizeStack(const StackTrace& trace);
|
|||
|
||||
void TsanCheckFailed(const char *file, int line, const char *cond,
|
||||
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: "
|
||||
"%s:%d \"%s\" (0x%zx, 0x%zx)\n",
|
||||
file, line, cond, (uptr)v1, (uptr)v2);
|
||||
|
@ -605,10 +608,12 @@ static bool RaceBetweenAtomicAndFree(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)
|
||||
return;
|
||||
ScopedInRtl in_rtl;
|
||||
|
||||
if (!flags()->report_atomic_races && !RaceBetweenAtomicAndFree(thr))
|
||||
return;
|
||||
|
||||
|
|
|
@ -189,7 +189,6 @@ static void ThreadCheckIgnore(ThreadState *thr) {}
|
|||
#endif
|
||||
|
||||
void ThreadFinalize(ThreadState *thr) {
|
||||
CHECK_GT(thr->in_rtl, 0);
|
||||
ThreadCheckIgnore(thr);
|
||||
#ifndef TSAN_GO
|
||||
if (!flags()->report_thread_leaks)
|
||||
|
@ -208,7 +207,6 @@ void ThreadFinalize(ThreadState *thr) {
|
|||
}
|
||||
|
||||
int ThreadCount(ThreadState *thr) {
|
||||
CHECK_GT(thr->in_rtl, 0);
|
||||
Context *ctx = CTX();
|
||||
uptr 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) {
|
||||
CHECK_GT(thr->in_rtl, 0);
|
||||
StatInc(thr, StatThreadCreate);
|
||||
Context *ctx = CTX();
|
||||
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) {
|
||||
Context *ctx = CTX();
|
||||
CHECK_GT(thr->in_rtl, 0);
|
||||
uptr stk_addr = 0;
|
||||
uptr stk_size = 0;
|
||||
uptr tls_addr = 0;
|
||||
|
@ -264,7 +260,6 @@ void ThreadStart(ThreadState *thr, int tid, uptr os_id) {
|
|||
}
|
||||
|
||||
void ThreadFinish(ThreadState *thr) {
|
||||
CHECK_GT(thr->in_rtl, 0);
|
||||
ThreadCheckIgnore(thr);
|
||||
StatInc(thr, StatThreadFinish);
|
||||
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) {
|
||||
CHECK_GT(thr->in_rtl, 0);
|
||||
Context *ctx = CTX();
|
||||
int res = ctx->thread_registry->FindThread(FindThreadByUid, (void*)uid);
|
||||
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) {
|
||||
CHECK_GT(thr->in_rtl, 0);
|
||||
CHECK_GT(tid, 0);
|
||||
CHECK_LT(tid, kMaxTid);
|
||||
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) {
|
||||
CHECK_GT(thr->in_rtl, 0);
|
||||
CHECK_GT(tid, 0);
|
||||
CHECK_LT(tid, kMaxTid);
|
||||
Context *ctx = CTX();
|
||||
|
@ -311,7 +303,6 @@ void ThreadDetach(ThreadState *thr, uptr pc, int tid) {
|
|||
}
|
||||
|
||||
void ThreadSetName(ThreadState *thr, const char *name) {
|
||||
CHECK_GT(thr->in_rtl, 0);
|
||||
CTX()->thread_registry->SetThreadName(thr->tid, name);
|
||||
}
|
||||
|
||||
|
|
|
@ -58,10 +58,18 @@ class Vector {
|
|||
return begin_[i];
|
||||
}
|
||||
|
||||
T *PushBack(T v = T()) {
|
||||
T *PushBack() {
|
||||
EnsureSize(Size() + 1);
|
||||
end_[-1] = v;
|
||||
return &end_[-1];
|
||||
T *p = &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() {
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
namespace __tsan {
|
||||
|
||||
TEST(Clock, VectorBasic) {
|
||||
ScopedInRtl in_rtl;
|
||||
ThreadClock clk;
|
||||
CHECK_EQ(clk.size(), 0);
|
||||
clk.tick(0);
|
||||
|
@ -34,7 +33,6 @@ TEST(Clock, VectorBasic) {
|
|||
}
|
||||
|
||||
TEST(Clock, ChunkedBasic) {
|
||||
ScopedInRtl in_rtl;
|
||||
ThreadClock vector;
|
||||
SyncClock chunked;
|
||||
CHECK_EQ(vector.size(), 0);
|
||||
|
@ -51,7 +49,6 @@ TEST(Clock, ChunkedBasic) {
|
|||
}
|
||||
|
||||
TEST(Clock, AcquireRelease) {
|
||||
ScopedInRtl in_rtl;
|
||||
ThreadClock vector1;
|
||||
vector1.tick(100);
|
||||
SyncClock chunked;
|
||||
|
@ -67,7 +64,6 @@ TEST(Clock, AcquireRelease) {
|
|||
}
|
||||
|
||||
TEST(Clock, ManyThreads) {
|
||||
ScopedInRtl in_rtl;
|
||||
SyncClock chunked;
|
||||
for (int i = 0; i < 100; i++) {
|
||||
ThreadClock vector;
|
||||
|
@ -85,7 +81,6 @@ TEST(Clock, ManyThreads) {
|
|||
}
|
||||
|
||||
TEST(Clock, DifferentSizes) {
|
||||
ScopedInRtl in_rtl;
|
||||
{
|
||||
ThreadClock vector1;
|
||||
vector1.tick(10);
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
namespace __tsan {
|
||||
|
||||
TEST(Flags, Basic) {
|
||||
ScopedInRtl in_rtl;
|
||||
// At least should not crash.
|
||||
Flags f;
|
||||
InitializeFlags(&f, 0);
|
||||
|
@ -26,7 +25,6 @@ TEST(Flags, Basic) {
|
|||
}
|
||||
|
||||
TEST(Flags, DefaultValues) {
|
||||
ScopedInRtl in_rtl;
|
||||
Flags f;
|
||||
|
||||
f.enable_annotations = false;
|
||||
|
@ -206,7 +204,6 @@ extern "C" const char *__tsan_default_options() {
|
|||
}
|
||||
|
||||
TEST(Flags, ParseDefaultOptions) {
|
||||
ScopedInRtl in_rtl;
|
||||
Flags f;
|
||||
|
||||
test_default_options = options1;
|
||||
|
@ -219,7 +216,6 @@ TEST(Flags, ParseDefaultOptions) {
|
|||
}
|
||||
|
||||
TEST(Flags, ParseEnvOptions) {
|
||||
ScopedInRtl in_rtl;
|
||||
Flags f;
|
||||
|
||||
InitializeFlags(&f, options1);
|
||||
|
@ -230,7 +226,6 @@ TEST(Flags, ParseEnvOptions) {
|
|||
}
|
||||
|
||||
TEST(Flags, ParsePriority) {
|
||||
ScopedInRtl in_rtl;
|
||||
Flags f;
|
||||
|
||||
test_default_options = options2;
|
||||
|
|
|
@ -28,7 +28,6 @@ uptr __tsan_get_allocated_size(void *p);
|
|||
namespace __tsan {
|
||||
|
||||
TEST(Mman, Internal) {
|
||||
ScopedInRtl in_rtl;
|
||||
char *p = (char*)internal_alloc(MBlockScopedBuf, 10);
|
||||
EXPECT_NE(p, (char*)0);
|
||||
char *p2 = (char*)internal_alloc(MBlockScopedBuf, 20);
|
||||
|
@ -45,7 +44,6 @@ TEST(Mman, Internal) {
|
|||
}
|
||||
|
||||
TEST(Mman, User) {
|
||||
ScopedInRtl in_rtl;
|
||||
ThreadState *thr = cur_thread();
|
||||
uptr pc = 0;
|
||||
char *p = (char*)user_alloc(thr, pc, 10);
|
||||
|
@ -72,7 +70,6 @@ TEST(Mman, User) {
|
|||
}
|
||||
|
||||
TEST(Mman, UserRealloc) {
|
||||
ScopedInRtl in_rtl;
|
||||
ThreadState *thr = cur_thread();
|
||||
uptr pc = 0;
|
||||
{
|
||||
|
@ -118,7 +115,6 @@ TEST(Mman, UserRealloc) {
|
|||
}
|
||||
|
||||
TEST(Mman, UsableSize) {
|
||||
ScopedInRtl in_rtl;
|
||||
ThreadState *thr = cur_thread();
|
||||
uptr pc = 0;
|
||||
char *p = (char*)user_alloc(thr, pc, 10);
|
||||
|
@ -131,7 +127,6 @@ TEST(Mman, UsableSize) {
|
|||
}
|
||||
|
||||
TEST(Mman, Stats) {
|
||||
ScopedInRtl in_rtl;
|
||||
ThreadState *thr = cur_thread();
|
||||
|
||||
uptr alloc0 = __tsan_get_current_allocated_bytes();
|
||||
|
|
|
@ -46,13 +46,11 @@ static void TestStackTrace(StackTrace *trace) {
|
|||
}
|
||||
|
||||
TEST(StackTrace, Basic) {
|
||||
ScopedInRtl in_rtl;
|
||||
StackTrace trace;
|
||||
TestStackTrace(&trace);
|
||||
}
|
||||
|
||||
TEST(StackTrace, StaticBasic) {
|
||||
ScopedInRtl in_rtl;
|
||||
uptr buf[10];
|
||||
StackTrace trace1(buf, 10);
|
||||
TestStackTrace(&trace1);
|
||||
|
@ -61,7 +59,6 @@ TEST(StackTrace, StaticBasic) {
|
|||
}
|
||||
|
||||
TEST(StackTrace, StaticTrim) {
|
||||
ScopedInRtl in_rtl;
|
||||
uptr buf[2];
|
||||
StackTrace trace(buf, 2);
|
||||
|
||||
|
|
|
@ -25,7 +25,6 @@ TEST(Sync, Table) {
|
|||
const uintptr_t kIters = 512*1024;
|
||||
const uintptr_t kRange = 10000;
|
||||
|
||||
ScopedInRtl in_rtl;
|
||||
ThreadState *thr = cur_thread();
|
||||
uptr pc = 0;
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
namespace __tsan {
|
||||
|
||||
TEST(Vector, Basic) {
|
||||
ScopedInRtl in_rtl;
|
||||
Vector<int> v(MBlockScopedBuf);
|
||||
EXPECT_EQ(v.Size(), (uptr)0);
|
||||
v.PushBack(42);
|
||||
|
@ -30,7 +29,6 @@ TEST(Vector, Basic) {
|
|||
}
|
||||
|
||||
TEST(Vector, Stride) {
|
||||
ScopedInRtl in_rtl;
|
||||
Vector<int> v(MBlockScopedBuf);
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
v.PushBack(i);
|
||||
|
|
Loading…
Reference in New Issue