tsan: better diagnostics for destroy of a locked mutex + a test


git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@162022 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/tsan/output_tests/mutex_destroy_locked.cc b/lib/tsan/output_tests/mutex_destroy_locked.cc
new file mode 100644
index 0000000..f6ab874
--- /dev/null
+++ b/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/lib/tsan/rtl/tsan_report.cc b/lib/tsan/rtl/tsan_report.cc
index c841a98..7fc2e16 100644
--- a/lib/tsan/rtl/tsan_report.cc
+++ b/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/lib/tsan/rtl/tsan_rtl.h b/lib/tsan/rtl/tsan_rtl.h
index 336b656..8568f0a 100644
--- a/lib/tsan/rtl/tsan_rtl.h
+++ b/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/lib/tsan/rtl/tsan_rtl_mutex.cc b/lib/tsan/rtl/tsan_rtl_mutex.cc
index 44c400b..258d203 100644
--- a/lib/tsan/rtl/tsan_rtl_mutex.cc
+++ b/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/lib/tsan/rtl/tsan_rtl_report.cc b/lib/tsan/rtl/tsan_rtl_report.cc
index f66e17e..6d1d49b 100644
--- a/lib/tsan/rtl/tsan_rtl_report.cc
+++ b/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/lib/tsan/rtl/tsan_sync.cc b/lib/tsan/rtl/tsan_sync.cc
index 2004c8e..1f798b2 100644
--- a/lib/tsan/rtl/tsan_sync.cc
+++ b/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/lib/tsan/rtl/tsan_sync.h b/lib/tsan/rtl/tsan_sync.h
index c967130..89de81d 100644
--- a/lib/tsan/rtl/tsan_sync.h
+++ b/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;