forked from OSchip/llvm-project
tsan: better reports for "double lock of a mutex"
+ fixes crashes due to races on symbolizer, see: https://code.google.com/p/thread-sanitizer/issues/detail?id=55 llvm-svn: 207204
This commit is contained in:
parent
3212b18bbf
commit
c845decce1
|
|
@ -41,6 +41,7 @@ static void ParseFlags(Flags *f, const char *env) {
|
|||
ParseFlag(env, &f->report_bugs, "report_bugs", "");
|
||||
ParseFlag(env, &f->report_thread_leaks, "report_thread_leaks", "");
|
||||
ParseFlag(env, &f->report_destroy_locked, "report_destroy_locked", "");
|
||||
ParseFlag(env, &f->report_mutex_bugs, "report_mutex_bugs", "");
|
||||
ParseFlag(env, &f->report_signal_unsafe, "report_signal_unsafe", "");
|
||||
ParseFlag(env, &f->report_atomic_races, "report_atomic_races", "");
|
||||
ParseFlag(env, &f->force_seq_cst_atomics, "force_seq_cst_atomics", "");
|
||||
|
|
@ -75,6 +76,7 @@ void InitializeFlags(Flags *f, const char *env) {
|
|||
f->report_bugs = true;
|
||||
f->report_thread_leaks = true;
|
||||
f->report_destroy_locked = true;
|
||||
f->report_mutex_bugs = true;
|
||||
f->report_signal_unsafe = true;
|
||||
f->report_atomic_races = true;
|
||||
f->force_seq_cst_atomics = false;
|
||||
|
|
|
|||
|
|
@ -37,6 +37,8 @@ struct Flags : CommonFlags, DDFlags {
|
|||
bool report_thread_leaks;
|
||||
// Report destruction of a locked mutex?
|
||||
bool report_destroy_locked;
|
||||
// Report incorrect usages of mutexes and mutex annotations?
|
||||
bool report_mutex_bugs;
|
||||
// Report violations of async signal-safety
|
||||
// (e.g. malloc() call from a signal handler).
|
||||
bool report_signal_unsafe;
|
||||
|
|
|
|||
|
|
@ -74,6 +74,8 @@ static const char *ReportTypeString(ReportType typ) {
|
|||
return "thread leak";
|
||||
if (typ == ReportTypeMutexDestroyLocked)
|
||||
return "destroy of a locked mutex";
|
||||
if (typ == ReportTypeMutexDoubleLock)
|
||||
return "double lock of a mutex";
|
||||
if (typ == ReportTypeSignalUnsafe)
|
||||
return "signal-unsafe call inside of a signal";
|
||||
if (typ == ReportTypeErrnoInSignal)
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ enum ReportType {
|
|||
ReportTypeUseAfterFree,
|
||||
ReportTypeThreadLeak,
|
||||
ReportTypeMutexDestroyLocked,
|
||||
ReportTypeMutexDoubleLock,
|
||||
ReportTypeSignalUnsafe,
|
||||
ReportTypeErrnoInSignal,
|
||||
ReportTypeDeadlock
|
||||
|
|
|
|||
|
|
@ -117,15 +117,16 @@ void MutexLock(ThreadState *thr, uptr pc, uptr addr, int rec, bool try_lock) {
|
|||
SyncVar *s = ctx->synctab.GetOrCreateAndLock(thr, pc, addr, true);
|
||||
thr->fast_state.IncrementEpoch();
|
||||
TraceAddEvent(thr, thr->fast_state, EventTypeLock, s->GetId());
|
||||
bool report_double_lock = false;
|
||||
if (s->owner_tid == SyncVar::kInvalidTid) {
|
||||
CHECK_EQ(s->recursion, 0);
|
||||
s->owner_tid = thr->tid;
|
||||
s->last_lock = thr->fast_state.raw();
|
||||
} else if (s->owner_tid == thr->tid) {
|
||||
CHECK_GT(s->recursion, 0);
|
||||
} else {
|
||||
Printf("ThreadSanitizer WARNING: double lock of mutex %p\n", addr);
|
||||
PrintCurrentStack(thr, pc);
|
||||
} else if (flags()->report_mutex_bugs && !s->is_broken) {
|
||||
s->is_broken = true;
|
||||
report_double_lock = true;
|
||||
}
|
||||
if (s->recursion == 0) {
|
||||
StatInc(thr, StatMutexLock);
|
||||
|
|
@ -142,7 +143,19 @@ void MutexLock(ThreadState *thr, uptr pc, uptr addr, int rec, bool try_lock) {
|
|||
ctx->dd->MutexBeforeLock(&cb, &s->dd, true);
|
||||
ctx->dd->MutexAfterLock(&cb, &s->dd, true, try_lock);
|
||||
}
|
||||
u64 mid = s->GetId();
|
||||
s->mtx.Unlock();
|
||||
// Can't touch s after this point.
|
||||
if (report_double_lock) {
|
||||
ThreadRegistryLock l(ctx->thread_registry);
|
||||
ScopedReport rep(ReportTypeMutexDoubleLock);
|
||||
rep.AddMutex(mid);
|
||||
StackTrace trace;
|
||||
trace.ObtainCurrent(thr, pc);
|
||||
rep.AddStack(&trace);
|
||||
rep.AddLocation(addr, 1);
|
||||
OutputReport(ctx, rep);
|
||||
}
|
||||
if (flags()->detect_deadlocks) {
|
||||
Callback cb(thr, pc);
|
||||
ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb));
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ static const char *options1 =
|
|||
" report_bugs=0"
|
||||
" report_thread_leaks=0"
|
||||
" report_destroy_locked=0"
|
||||
" report_mutex_bugs=0"
|
||||
" report_signal_unsafe=0"
|
||||
" report_atomic_races=0"
|
||||
" force_seq_cst_atomics=0"
|
||||
|
|
@ -86,6 +87,7 @@ static const char *options2 =
|
|||
" report_bugs=true"
|
||||
" report_thread_leaks=true"
|
||||
" report_destroy_locked=true"
|
||||
" report_mutex_bugs=true"
|
||||
" report_signal_unsafe=true"
|
||||
" report_atomic_races=true"
|
||||
" force_seq_cst_atomics=true"
|
||||
|
|
@ -130,6 +132,7 @@ void VerifyOptions1(Flags *f) {
|
|||
EXPECT_EQ(f->report_bugs, 0);
|
||||
EXPECT_EQ(f->report_thread_leaks, 0);
|
||||
EXPECT_EQ(f->report_destroy_locked, 0);
|
||||
EXPECT_EQ(f->report_mutex_bugs, 0);
|
||||
EXPECT_EQ(f->report_signal_unsafe, 0);
|
||||
EXPECT_EQ(f->report_atomic_races, 0);
|
||||
EXPECT_EQ(f->force_seq_cst_atomics, 0);
|
||||
|
|
@ -174,6 +177,7 @@ void VerifyOptions2(Flags *f) {
|
|||
EXPECT_EQ(f->report_bugs, true);
|
||||
EXPECT_EQ(f->report_thread_leaks, true);
|
||||
EXPECT_EQ(f->report_destroy_locked, true);
|
||||
EXPECT_EQ(f->report_mutex_bugs, true);
|
||||
EXPECT_EQ(f->report_signal_unsafe, true);
|
||||
EXPECT_EQ(f->report_atomic_races, true);
|
||||
EXPECT_EQ(f->force_seq_cst_atomics, true);
|
||||
|
|
|
|||
Loading…
Reference in New Issue