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:
Dmitry Vyukov 2014-04-25 07:42:55 +00:00
parent 3212b18bbf
commit c845decce1
6 changed files with 27 additions and 3 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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)

View File

@ -24,6 +24,7 @@ enum ReportType {
ReportTypeUseAfterFree,
ReportTypeThreadLeak,
ReportTypeMutexDestroyLocked,
ReportTypeMutexDoubleLock,
ReportTypeSignalUnsafe,
ReportTypeErrnoInSignal,
ReportTypeDeadlock

View File

@ -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));

View File

@ -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);