summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2014-04-25 08:58:23 +0000
committerDmitry Vyukov <dvyukov@google.com>2014-04-25 08:58:23 +0000
commitaf11ce221730ad4056c5d541819e95b795fba103 (patch)
tree04fe68b5bc60f8c7221fc942f564c1f52a7a5100
parent2a10d45fc5321f31c5a0cb8ccf8e17c5d2a67ed2 (diff)
tsan: better reports for "read lock of a write locked mutex"
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@207209 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/tsan/rtl/tsan_report.cc2
-rw-r--r--lib/tsan/rtl/tsan_report.h1
-rw-r--r--lib/tsan/rtl/tsan_rtl_mutex.cc60
-rw-r--r--test/tsan/mutex_bad_read_lock.cc19
4 files changed, 49 insertions, 33 deletions
diff --git a/lib/tsan/rtl/tsan_report.cc b/lib/tsan/rtl/tsan_report.cc
index 98a7d0f4d..a835cee7d 100644
--- a/lib/tsan/rtl/tsan_report.cc
+++ b/lib/tsan/rtl/tsan_report.cc
@@ -78,6 +78,8 @@ static const char *ReportTypeString(ReportType typ) {
return "double lock of a mutex";
if (typ == ReportTypeMutexBadUnlock)
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)
return "read unlock of a write locked mutex";
if (typ == ReportTypeSignalUnsafe)
diff --git a/lib/tsan/rtl/tsan_report.h b/lib/tsan/rtl/tsan_report.h
index 7c14eff18..3817bcdfc 100644
--- a/lib/tsan/rtl/tsan_report.h
+++ b/lib/tsan/rtl/tsan_report.h
@@ -26,6 +26,7 @@ enum ReportType {
ReportTypeMutexDestroyLocked,
ReportTypeMutexDoubleLock,
ReportTypeMutexBadUnlock,
+ ReportTypeMutexBadReadLock,
ReportTypeMutexBadReadUnlock,
ReportTypeSignalUnsafe,
ReportTypeErrnoInSignal,
diff --git a/lib/tsan/rtl/tsan_rtl_mutex.cc b/lib/tsan/rtl/tsan_rtl_mutex.cc
index ae6e4f798..5cb06a870 100644
--- a/lib/tsan/rtl/tsan_rtl_mutex.cc
+++ b/lib/tsan/rtl/tsan_rtl_mutex.cc
@@ -50,6 +50,18 @@ void DDMutexInit(ThreadState *thr, uptr pc, SyncVar *s) {
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,
bool rw, bool recursive, bool linker_init) {
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();
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 (report_double_lock)
+ ReportMutexMisuse(thr, pc, ReportTypeMutexDoubleLock, addr, mid);
if (flags()->detect_deadlocks) {
Callback cb(thr, pc);
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();
s->mtx.Unlock();
// Can't touch s after this point.
- if (report_bad_unlock) {
- ThreadRegistryLock l(ctx->thread_registry);
- ScopedReport rep(ReportTypeMutexBadUnlock);
- rep.AddMutex(mid);
- StackTrace trace;
- trace.ObtainCurrent(thr, pc);
- rep.AddStack(&trace);
- rep.AddLocation(addr, 1);
- OutputReport(ctx, rep);
- }
+ if (report_bad_unlock)
+ ReportMutexMisuse(thr, pc, ReportTypeMutexBadUnlock, addr, mid);
if (flags()->detect_deadlocks) {
Callback cb(thr, pc);
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);
thr->fast_state.IncrementEpoch();
TraceAddEvent(thr, thr->fast_state, EventTypeRLock, s->GetId());
+ bool report_bad_lock = false;
if (s->owner_tid != SyncVar::kInvalidTid) {
- Printf("ThreadSanitizer WARNING: read lock of a write locked mutex %p\n",
- addr);
- PrintCurrentStack(thr, pc);
+ if (flags()->report_mutex_bugs && !s->is_broken) {
+ s->is_broken = true;
+ report_bad_lock = true;
+ }
}
AcquireImpl(thr, pc, &s->clock);
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->MutexAfterLock(&cb, &s->dd, false, trylock);
}
+ u64 mid = s->GetId();
s->mtx.ReadUnlock();
+ // Can't touch s after this point.
+ if (report_bad_lock)
+ ReportMutexMisuse(thr, pc, ReportTypeMutexBadReadLock, addr, mid);
if (flags()->detect_deadlocks) {
Callback cb(thr, pc);
ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb));
@@ -265,16 +267,8 @@ void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr) {
s->mtx.Unlock();
// Can't touch s after this point.
thr->mset.Del(mid, false);
- if (report_bad_unlock) {
- ThreadRegistryLock l(ctx->thread_registry);
- ScopedReport rep(ReportTypeMutexBadReadUnlock);
- rep.AddMutex(mid);
- StackTrace trace;
- trace.ObtainCurrent(thr, pc);
- rep.AddStack(&trace);
- rep.AddLocation(addr, 1);
- OutputReport(ctx, rep);
- }
+ if (report_bad_unlock)
+ ReportMutexMisuse(thr, pc, ReportTypeMutexBadReadUnlock, addr, mid);
if (flags()->detect_deadlocks) {
Callback cb(thr, pc);
ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb));
diff --git a/test/tsan/mutex_bad_read_lock.cc b/test/tsan/mutex_bad_read_lock.cc
new file mode 100644
index 000000000..0f348f53e
--- /dev/null
+++ b/test/tsan/mutex_bad_read_lock.cc
@@ -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
+