diff options
5 files changed, 39 insertions, 23 deletions
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector.h b/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector.h index a3731017858..a75612a032f 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector.h @@ -231,20 +231,24 @@ class DeadlockDetector { added_edges, ARRAY_SIZE(added_edges)); for (uptr i = 0; i < n_added_edges; i++) { if (n_edges_ < ARRAY_SIZE(edges_)) - edges_[n_edges_++] = Edge((u16)added_edges[i], (u16)cur_idx, stk); + edges_[n_edges_++] = Edge((u16)added_edges[i], (u16)cur_idx, stk, + dtls->findLockContext(added_edges[i])); // Printf("Edge [%zd]: %u %zd=>%zd\n", i, stk, added_edges[i], cur_idx); } return n_added_edges; } - u32 findEdge(uptr from_node, uptr to_node) { + bool findEdge(uptr from_node, uptr to_node, u32 *stk_from, u32 *stk_to) { uptr from_idx = nodeToIndex(from_node); uptr to_idx = nodeToIndex(to_node); for (uptr i = 0; i < n_edges_; i++) { - if (edges_[i].from == from_idx && edges_[i].to == to_idx) - return edges_[i].stk; + if (edges_[i].from == from_idx && edges_[i].to == to_idx) { + *stk_from = edges_[i].stk_from; + *stk_to = edges_[i].stk_to; + return true; + } } - return 0; + return false; } // Test-only function. Handles the before/after lock events, @@ -367,9 +371,11 @@ class DeadlockDetector { struct Edge { u16 from; u16 to; - u32 stk; + u32 stk_from; + u32 stk_to; // FIXME: replace with initializer list once the tests are built as c++11. - Edge(u16 f, u16 t, u32 s) : from(f), to(t), stk(s) {} + Edge(u16 f, u16 t, u32 sf, u32 st) + : from(f), to(t), stk_from(sf), stk_to(st) {} Edge() {} }; diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector1.cc b/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector1.cc index d633c843d4e..368bd41be83 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector1.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector1.cc @@ -106,9 +106,12 @@ void DD::MutexBeforeLock(DDCallback *cb, if (dd.isHeld(<->dd, m->id)) return; // FIXME: allow this only for recursive locks. if (dd.onLockBefore(<->dd, m->id)) { + // Actually add this edge now so that we have all the stack traces. + dd.addEdges(<->dd, m->id, cb->Unwind()); uptr path[10]; uptr len = dd.findPathToLock(<->dd, m->id, path, ARRAY_SIZE(path)); CHECK_GT(len, 0U); // Hm.. cycle of 10 locks? I'd like to see that. + CHECK_EQ(m->id, path[0]); lt->report_pending = true; DDReport *rep = <->rep; rep->n = len; @@ -118,22 +121,25 @@ void DD::MutexBeforeLock(DDCallback *cb, DDMutex *m0 = (DDMutex*)dd.getData(from); DDMutex *m1 = (DDMutex*)dd.getData(to); - u32 stk = dd.findEdge(from, to); - // Printf("Edge: %zd=>%zd: %u\n", from, to, stk); + u32 stk_from = 0, stk_to = 0; + dd.findEdge(from, to, &stk_from, &stk_to); + // Printf("Edge: %zd=>%zd: %u/%u\n", from, to, stk_from, stk_to); rep->loop[i].thr_ctx = 0; // don't know rep->loop[i].mtx_ctx0 = m0->ctx; rep->loop[i].mtx_ctx1 = m1->ctx; - rep->loop[i].stk = stk; + rep->loop[i].stk[0] = stk_from; + rep->loop[i].stk[1] = stk_to; } } } void DD::MutexAfterLock(DDCallback *cb, DDMutex *m, bool wlock, bool trylock) { DDLogicalThread *lt = cb->lt; + u32 stk = cb->Unwind(); // FIXME: if this is hot, do this under a flag. // Printf("T%p MutexLock: %zx\n", lt, m->id); - if (dd.onFirstLock(<->dd, m->id)) + if (dd.onFirstLock(<->dd, m->id, stk)) return; - if (dd.onLockFast(<->dd, m->id)) + if (dd.onLockFast(<->dd, m->id, stk)) return; SpinMutexLock lk(&mtx); @@ -142,7 +148,7 @@ void DD::MutexAfterLock(DDCallback *cb, DDMutex *m, bool wlock, bool trylock) { CHECK(!dd.isHeld(<->dd, m->id)); if (!trylock) dd.addEdges(<->dd, m->id, cb->Unwind()); - dd.onLockAfter(<->dd, m->id); + dd.onLockAfter(<->dd, m->id, stk); } void DD::MutexBeforeUnlock(DDCallback *cb, DDMutex *m, bool wlock) { diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector_interface.h b/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector_interface.h index 5d1ecf42830..9c5dc8f4b5a 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector_interface.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_deadlock_detector_interface.h @@ -47,13 +47,13 @@ struct DDMutex { }; struct DDReport { - enum { kMaxLoopSize = 16 }; + enum { kMaxLoopSize = 8 }; int n; // number of entries in loop struct { u64 thr_ctx; // user thread context u64 mtx_ctx0; // user mutex context, start of the edge u64 mtx_ctx1; // user mutex context, end of the edge - u32 stk; // stack id for the edge + u32 stk[2]; // stack ids for the edge } loop[kMaxLoopSize]; }; diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cc b/compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cc index bbf6886ae6e..8398e4b4522 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cc +++ b/compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cc @@ -427,17 +427,17 @@ void ReportDeadlock(ThreadState *thr, uptr pc, DDReport *r) { ScopedReport rep(ReportTypeDeadlock); for (int i = 0; i < r->n; i++) rep.AddMutex(r->loop[i].mtx_ctx0); - StackTrace stacks[DDReport::kMaxLoopSize]; + StackTrace stacks[2 * DDReport::kMaxLoopSize]; for (int i = 0; i < r->n; i++) { - if (!r->loop[i].stk) continue; uptr size; - const uptr *trace = StackDepotGet(r->loop[i].stk, &size); - stacks[i].Init(const_cast<uptr *>(trace), size); - rep.AddStack(&stacks[i]); + for (int j = 0; j < 2; j++) { + u32 stk = r->loop[i].stk[j]; + if (!stk) continue; + const uptr *trace = StackDepotGet(stk, &size); + stacks[i].Init(const_cast<uptr *>(trace), size); + rep.AddStack(&stacks[i]); + } } - StackTrace trace; - trace.ObtainCurrent(thr, pc); - rep.AddStack(&trace); OutputReport(ctx, rep); #endif // TSAN_GO } diff --git a/compiler-rt/test/tsan/deadlock_detector_stress_test.cc b/compiler-rt/test/tsan/deadlock_detector_stress_test.cc index 0a3d9ed4f14..a85c2e891ff 100644 --- a/compiler-rt/test/tsan/deadlock_detector_stress_test.cc +++ b/compiler-rt/test/tsan/deadlock_detector_stress_test.cc @@ -420,6 +420,10 @@ class LockTest { // CHECK: LockTest::Acquire1 // CHECK-NEXT: LockTest::Acquire_0_then_1 // CHECK: LockTest::Acquire0 + // CHECK-NEXT: LockTest::Acquire_0_then_1 + // CHECK: LockTest::Acquire0 + // CHECK-NEXT: LockTest::Acquire_1_then_0 + // CHECK: LockTest::Acquire1 // CHECK-NEXT: LockTest::Acquire_1_then_0 Init(5); Acquire_0_then_1(); |