tsan: better diagnostics for destroy of a locked mutex + a test
llvm-svn: 162022
diff --git a/compiler-rt/lib/tsan/output_tests/mutex_destroy_locked.cc b/compiler-rt/lib/tsan/output_tests/mutex_destroy_locked.cc
new file mode 100644
index 0000000..f6ab874
--- /dev/null
+++ b/compiler-rt/lib/tsan/output_tests/mutex_destroy_locked.cc
@@ -0,0 +1,29 @@
+#include <pthread.h>
+#include <unistd.h>
+
+void *Thread(void *p) {
+ pthread_mutex_lock((pthread_mutex_t*)p);
+ return 0;
+}
+
+int main() {
+ pthread_mutex_t m;
+ pthread_mutex_init(&m, 0);
+ pthread_t t;
+ pthread_create(&t, 0, Thread, &m);
+ usleep(1000*1000);
+ pthread_mutex_destroy(&m);
+ pthread_join(t, 0);
+ return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: destroy of a locked mutex
+// CHECK: #0 pthread_mutex_destroy
+// CHECK: #1 main
+// CHECK: and:
+// CHECK: #0 pthread_mutex_lock
+// CHECK: #1 Thread
+// CHECK: Mutex {{.*}} created at:
+// CHECK: #0 pthread_mutex_init
+// CHECK: #1 main
+
diff --git a/compiler-rt/lib/tsan/rtl/tsan_report.cc b/compiler-rt/lib/tsan/rtl/tsan_report.cc
index c841a98..7fc2e16 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_report.cc
+++ b/compiler-rt/lib/tsan/rtl/tsan_report.cc
@@ -109,8 +109,11 @@
TsanPrintf("==================\n");
PrintHeader(rep->typ);
- for (uptr i = 0; i < rep->stacks.Size(); i++)
+ for (uptr i = 0; i < rep->stacks.Size(); i++) {
+ if (i)
+ TsanPrintf(" and:\n");
PrintStack(rep->stacks[i]);
+ }
for (uptr i = 0; i < rep->mops.Size(); i++)
PrintMop(rep->mops[i], i == 0);
diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl.h b/compiler-rt/lib/tsan/rtl/tsan_rtl.h
index 336b656..8568f0a 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_rtl.h
+++ b/compiler-rt/lib/tsan/rtl/tsan_rtl.h
@@ -83,6 +83,10 @@
: x_(x) {
}
+ u64 raw() const {
+ return x_;
+ }
+
u64 tid() const {
u64 res = x_ >> kTidShift;
return res;
@@ -143,7 +147,6 @@
}
bool IsZero() const { return x_ == 0; }
- u64 raw() const { return x_; }
static inline bool TidsAreEqual(const Shadow s1, const Shadow s2) {
u64 shifted_xor = (s1.x_ ^ s2.x_) >> kTidShift;
@@ -409,6 +412,8 @@
void operator = (const ScopedReport&);
};
+void RestoreStack(int tid, const u64 epoch, StackTrace *stk);
+
void StatAggregate(u64 *dst, u64 *src);
void StatOutput(u64 *stat);
void ALWAYS_INLINE INLINE StatInc(ThreadState *thr, StatType typ, u64 n = 1) {
diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cc b/compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cc
index 44c400b..258d203 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cc
+++ b/compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cc
@@ -47,6 +47,12 @@
s->is_broken = true;
ScopedReport rep(ReportTypeMutexDestroyLocked);
rep.AddMutex(s);
+ StackTrace trace;
+ trace.ObtainCurrent(thr, pc);
+ rep.AddStack(&trace);
+ FastState last(s->last_lock);
+ RestoreStack(last.tid(), last.epoch(), &trace);
+ rep.AddStack(&trace);
rep.AddLocation(s->addr, 1);
OutputReport(rep);
}
@@ -64,6 +70,7 @@
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 {
@@ -128,6 +135,7 @@
TsanPrintf("ThreadSanitizer WARNING: read lock of a write locked mutex\n");
thr->clock.set(thr->tid, thr->fast_state.epoch());
thr->clock.acquire(&s->clock);
+ s->last_lock = thr->fast_state.raw();
StatInc(thr, StatSyncAcquire);
s->mtx.ReadUnlock();
}
diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cc b/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cc
index f66e17e..6d1d49b 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cc
+++ b/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cc
@@ -188,7 +188,7 @@
return rep_;
}
-static void RestoreStack(int tid, const u64 epoch, StackTrace *stk) {
+void RestoreStack(int tid, const u64 epoch, StackTrace *stk) {
ThreadContext *tctx = CTX()->threads[tid];
if (tctx == 0)
return;
diff --git a/compiler-rt/lib/tsan/rtl/tsan_sync.cc b/compiler-rt/lib/tsan/rtl/tsan_sync.cc
index 2004c8e..1f798b2 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_sync.cc
+++ b/compiler-rt/lib/tsan/rtl/tsan_sync.cc
@@ -21,6 +21,7 @@
: mtx(MutexTypeSyncVar, StatMtxSyncVar)
, addr(addr)
, owner_tid(kInvalidTid)
+ , last_lock()
, recursion()
, is_rw()
, is_recursive()
diff --git a/compiler-rt/lib/tsan/rtl/tsan_sync.h b/compiler-rt/lib/tsan/rtl/tsan_sync.h
index c967130..89de81d 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_sync.h
+++ b/compiler-rt/lib/tsan/rtl/tsan_sync.h
@@ -60,6 +60,7 @@
SyncClock read_clock; // Used for rw mutexes only.
StackTrace creation_stack;
int owner_tid; // Set only by exclusive owners.
+ u64 last_lock;
int recursion;
bool is_rw;
bool is_recursive;