forked from OSchip/llvm-project
tsan: better reports for "read lock of a write locked mutex"
llvm-svn: 207209
This commit is contained in:
parent
e296164f77
commit
56a18f02ea
|
|
@ -78,6 +78,8 @@ static const char *ReportTypeString(ReportType typ) {
|
||||||
return "double lock of a mutex";
|
return "double lock of a mutex";
|
||||||
if (typ == ReportTypeMutexBadUnlock)
|
if (typ == ReportTypeMutexBadUnlock)
|
||||||
return "unlock of an unlocked mutex (or by a wrong thread)";
|
return "unlock of an unlocked mutex (or by a wrong thread)";
|
||||||
|
if (typ == ReportTypeMutexBadReadLock)
|
||||||
|
return "read lock of a write locked mutex";
|
||||||
if (typ == ReportTypeMutexBadReadUnlock)
|
if (typ == ReportTypeMutexBadReadUnlock)
|
||||||
return "read unlock of a write locked mutex";
|
return "read unlock of a write locked mutex";
|
||||||
if (typ == ReportTypeSignalUnsafe)
|
if (typ == ReportTypeSignalUnsafe)
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ enum ReportType {
|
||||||
ReportTypeMutexDestroyLocked,
|
ReportTypeMutexDestroyLocked,
|
||||||
ReportTypeMutexDoubleLock,
|
ReportTypeMutexDoubleLock,
|
||||||
ReportTypeMutexBadUnlock,
|
ReportTypeMutexBadUnlock,
|
||||||
|
ReportTypeMutexBadReadLock,
|
||||||
ReportTypeMutexBadReadUnlock,
|
ReportTypeMutexBadReadUnlock,
|
||||||
ReportTypeSignalUnsafe,
|
ReportTypeSignalUnsafe,
|
||||||
ReportTypeErrnoInSignal,
|
ReportTypeErrnoInSignal,
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,18 @@ void DDMutexInit(ThreadState *thr, uptr pc, SyncVar *s) {
|
||||||
s->dd.ctx = s->GetId();
|
s->dd.ctx = s->GetId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ReportMutexMisuse(ThreadState *thr, uptr pc, ReportType typ,
|
||||||
|
uptr addr, u64 mid) {
|
||||||
|
ThreadRegistryLock l(ctx->thread_registry);
|
||||||
|
ScopedReport rep(typ);
|
||||||
|
rep.AddMutex(mid);
|
||||||
|
StackTrace trace;
|
||||||
|
trace.ObtainCurrent(thr, pc);
|
||||||
|
rep.AddStack(&trace);
|
||||||
|
rep.AddLocation(addr, 1);
|
||||||
|
OutputReport(ctx, rep);
|
||||||
|
}
|
||||||
|
|
||||||
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) {
|
||||||
DPrintf("#%d: MutexCreate %zx\n", thr->tid, addr);
|
DPrintf("#%d: MutexCreate %zx\n", thr->tid, addr);
|
||||||
|
|
@ -146,16 +158,8 @@ void MutexLock(ThreadState *thr, uptr pc, uptr addr, int rec, bool try_lock) {
|
||||||
u64 mid = s->GetId();
|
u64 mid = s->GetId();
|
||||||
s->mtx.Unlock();
|
s->mtx.Unlock();
|
||||||
// Can't touch s after this point.
|
// Can't touch s after this point.
|
||||||
if (report_double_lock) {
|
if (report_double_lock)
|
||||||
ThreadRegistryLock l(ctx->thread_registry);
|
ReportMutexMisuse(thr, pc, ReportTypeMutexDoubleLock, addr, mid);
|
||||||
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) {
|
if (flags()->detect_deadlocks) {
|
||||||
Callback cb(thr, pc);
|
Callback cb(thr, pc);
|
||||||
ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb));
|
ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb));
|
||||||
|
|
@ -195,16 +199,8 @@ int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, bool all) {
|
||||||
u64 mid = s->GetId();
|
u64 mid = s->GetId();
|
||||||
s->mtx.Unlock();
|
s->mtx.Unlock();
|
||||||
// Can't touch s after this point.
|
// Can't touch s after this point.
|
||||||
if (report_bad_unlock) {
|
if (report_bad_unlock)
|
||||||
ThreadRegistryLock l(ctx->thread_registry);
|
ReportMutexMisuse(thr, pc, ReportTypeMutexBadUnlock, addr, mid);
|
||||||
ScopedReport rep(ReportTypeMutexBadUnlock);
|
|
||||||
rep.AddMutex(mid);
|
|
||||||
StackTrace trace;
|
|
||||||
trace.ObtainCurrent(thr, pc);
|
|
||||||
rep.AddStack(&trace);
|
|
||||||
rep.AddLocation(addr, 1);
|
|
||||||
OutputReport(ctx, rep);
|
|
||||||
}
|
|
||||||
if (flags()->detect_deadlocks) {
|
if (flags()->detect_deadlocks) {
|
||||||
Callback cb(thr, pc);
|
Callback cb(thr, pc);
|
||||||
ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb));
|
ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb));
|
||||||
|
|
@ -220,10 +216,12 @@ void MutexReadLock(ThreadState *thr, uptr pc, uptr addr, bool trylock) {
|
||||||
SyncVar *s = ctx->synctab.GetOrCreateAndLock(thr, pc, addr, false);
|
SyncVar *s = ctx->synctab.GetOrCreateAndLock(thr, pc, addr, false);
|
||||||
thr->fast_state.IncrementEpoch();
|
thr->fast_state.IncrementEpoch();
|
||||||
TraceAddEvent(thr, thr->fast_state, EventTypeRLock, s->GetId());
|
TraceAddEvent(thr, thr->fast_state, EventTypeRLock, s->GetId());
|
||||||
|
bool report_bad_lock = false;
|
||||||
if (s->owner_tid != SyncVar::kInvalidTid) {
|
if (s->owner_tid != SyncVar::kInvalidTid) {
|
||||||
Printf("ThreadSanitizer WARNING: read lock of a write locked mutex %p\n",
|
if (flags()->report_mutex_bugs && !s->is_broken) {
|
||||||
addr);
|
s->is_broken = true;
|
||||||
PrintCurrentStack(thr, pc);
|
report_bad_lock = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
AcquireImpl(thr, pc, &s->clock);
|
AcquireImpl(thr, pc, &s->clock);
|
||||||
s->last_lock = thr->fast_state.raw();
|
s->last_lock = thr->fast_state.raw();
|
||||||
|
|
@ -234,7 +232,11 @@ void MutexReadLock(ThreadState *thr, uptr pc, uptr addr, bool trylock) {
|
||||||
ctx->dd->MutexBeforeLock(&cb, &s->dd, false);
|
ctx->dd->MutexBeforeLock(&cb, &s->dd, false);
|
||||||
ctx->dd->MutexAfterLock(&cb, &s->dd, false, trylock);
|
ctx->dd->MutexAfterLock(&cb, &s->dd, false, trylock);
|
||||||
}
|
}
|
||||||
|
u64 mid = s->GetId();
|
||||||
s->mtx.ReadUnlock();
|
s->mtx.ReadUnlock();
|
||||||
|
// Can't touch s after this point.
|
||||||
|
if (report_bad_lock)
|
||||||
|
ReportMutexMisuse(thr, pc, ReportTypeMutexBadReadLock, addr, mid);
|
||||||
if (flags()->detect_deadlocks) {
|
if (flags()->detect_deadlocks) {
|
||||||
Callback cb(thr, pc);
|
Callback cb(thr, pc);
|
||||||
ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb));
|
ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb));
|
||||||
|
|
@ -265,16 +267,8 @@ void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr) {
|
||||||
s->mtx.Unlock();
|
s->mtx.Unlock();
|
||||||
// Can't touch s after this point.
|
// Can't touch s after this point.
|
||||||
thr->mset.Del(mid, false);
|
thr->mset.Del(mid, false);
|
||||||
if (report_bad_unlock) {
|
if (report_bad_unlock)
|
||||||
ThreadRegistryLock l(ctx->thread_registry);
|
ReportMutexMisuse(thr, pc, ReportTypeMutexBadReadUnlock, addr, mid);
|
||||||
ScopedReport rep(ReportTypeMutexBadReadUnlock);
|
|
||||||
rep.AddMutex(mid);
|
|
||||||
StackTrace trace;
|
|
||||||
trace.ObtainCurrent(thr, pc);
|
|
||||||
rep.AddStack(&trace);
|
|
||||||
rep.AddLocation(addr, 1);
|
|
||||||
OutputReport(ctx, rep);
|
|
||||||
}
|
|
||||||
if (flags()->detect_deadlocks) {
|
if (flags()->detect_deadlocks) {
|
||||||
Callback cb(thr, pc);
|
Callback cb(thr, pc);
|
||||||
ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb));
|
ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb));
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
|
||||||
|
extern "C" void AnnotateRWLockAcquired(const char *f, int l, void *m, long rw);
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
int m = 0;
|
||||||
|
AnnotateRWLockAcquired(__FILE__, __LINE__, &m, 1);
|
||||||
|
AnnotateRWLockAcquired(__FILE__, __LINE__, &m, 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CHECK: WARNING: ThreadSanitizer: read lock of a write locked mutex
|
||||||
|
// CHECK: #0 AnnotateRWLockAcquired
|
||||||
|
// CHECK: #1 main
|
||||||
|
// CHECK: Location is stack of main thread.
|
||||||
|
// CHECK: Mutex {{.*}}) created at:
|
||||||
|
// CHECK: #0 AnnotateRWLockAcquired
|
||||||
|
// CHECK: #1 main
|
||||||
|
// CHECK: SUMMARY: ThreadSanitizer: read lock of a write locked mutex
|
||||||
|
|
||||||
Loading…
Reference in New Issue