forked from OSchip/llvm-project
[tsan] when printing a mutex, also print its address. Properly print the deadlock report.
llvm-svn: 201675
This commit is contained in:
parent
8067448dfe
commit
b51f8d4990
|
|
@ -77,6 +77,8 @@ static const char *ReportTypeString(ReportType typ) {
|
|||
return "signal-unsafe call inside of a signal";
|
||||
if (typ == ReportTypeErrnoInSignal)
|
||||
return "signal handler spoils errno";
|
||||
if (typ == ReportTypeDeadlock)
|
||||
return "lock-order-inversion (potential deadlock)";
|
||||
return "";
|
||||
}
|
||||
|
||||
|
|
@ -155,6 +157,11 @@ static void PrintLocation(const ReportLocation *loc) {
|
|||
PrintStack(loc->stack);
|
||||
}
|
||||
|
||||
static void PrintMutexShort(const ReportMutex *rm, const char *after) {
|
||||
Decorator d;
|
||||
Printf("%sM%zd%s%s", d.Mutex(), rm->id, d.EndMutex(), after);
|
||||
}
|
||||
|
||||
static void PrintMutex(const ReportMutex *rm) {
|
||||
Decorator d;
|
||||
if (rm->destroyed) {
|
||||
|
|
@ -163,7 +170,7 @@ static void PrintMutex(const ReportMutex *rm) {
|
|||
Printf("%s", d.EndMutex());
|
||||
} else {
|
||||
Printf("%s", d.Mutex());
|
||||
Printf(" Mutex M%llu created at:\n", rm->id);
|
||||
Printf(" Mutex M%llu (%p) created at:\n", rm->id, rm->addr);
|
||||
Printf("%s", d.EndMutex());
|
||||
PrintStack(rm->stack);
|
||||
}
|
||||
|
|
@ -223,6 +230,14 @@ void PrintReport(const ReportDesc *rep) {
|
|||
(int)internal_getpid());
|
||||
Printf("%s", d.EndWarning());
|
||||
|
||||
if (rep->typ == ReportTypeDeadlock) {
|
||||
Printf(" path: ");
|
||||
CHECK_GT(rep->mutexes.Size(), 0U);
|
||||
for (uptr i = 0; i < rep->mutexes.Size(); i++)
|
||||
PrintMutexShort(rep->mutexes[i], " => ");
|
||||
PrintMutexShort(rep->mutexes[0], "\n");
|
||||
}
|
||||
|
||||
for (uptr i = 0; i < rep->stacks.Size(); i++) {
|
||||
if (i)
|
||||
Printf(" and:\n");
|
||||
|
|
|
|||
|
|
@ -25,7 +25,8 @@ enum ReportType {
|
|||
ReportTypeThreadLeak,
|
||||
ReportTypeMutexDestroyLocked,
|
||||
ReportTypeSignalUnsafe,
|
||||
ReportTypeErrnoInSignal
|
||||
ReportTypeErrnoInSignal,
|
||||
ReportTypeDeadlock
|
||||
};
|
||||
|
||||
struct ReportStack {
|
||||
|
|
@ -89,6 +90,7 @@ struct ReportThread {
|
|||
|
||||
struct ReportMutex {
|
||||
u64 id;
|
||||
uptr addr;
|
||||
bool destroyed;
|
||||
ReportStack *stack;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ static __sanitizer::DeadlockDetector<DDBV> g_dd;
|
|||
|
||||
static void EnsureDeadlockDetectorID(ThreadState *thr, SyncVar *s) {
|
||||
if (!g_dd.nodeBelongsToCurrentEpoch(s->deadlock_detector_id))
|
||||
s->deadlock_detector_id = g_dd.newNode(reinterpret_cast<uptr>(s->addr));
|
||||
s->deadlock_detector_id = g_dd.newNode(reinterpret_cast<uptr>(s));
|
||||
}
|
||||
|
||||
void MutexCreate(ThreadState *thr, uptr pc, uptr addr,
|
||||
|
|
@ -128,17 +128,19 @@ void MutexLock(ThreadState *thr, uptr pc, uptr addr, int rec) {
|
|||
bool has_deadlock =
|
||||
g_dd.onLock(&thr->deadlock_detector_tls, s->deadlock_detector_id);
|
||||
if (has_deadlock) {
|
||||
Printf("ThreadSanitizer: lock-order-inversion (potential deadlock)\n");
|
||||
uptr path[10];
|
||||
uptr len = g_dd.findPathToHeldLock(&thr->deadlock_detector_tls,
|
||||
s->deadlock_detector_id, path,
|
||||
ARRAY_SIZE(path));
|
||||
CHECK_GT(len, 0U); // Hm.. cycle of 10 locks? I'd like to see that.
|
||||
Printf(" path: ");
|
||||
for (uptr i = 0; i < len; i++) {
|
||||
Printf("%p => ", g_dd.getData(path[i]));
|
||||
}
|
||||
Printf("%p\n", g_dd.getData(path[0]));
|
||||
ThreadRegistryLock l(CTX()->thread_registry);
|
||||
ScopedReport rep(ReportTypeDeadlock);
|
||||
for (uptr i = 0; i < len; i++)
|
||||
rep.AddMutex(reinterpret_cast<SyncVar*>(g_dd.getData(path[i])));
|
||||
StackTrace trace;
|
||||
trace.ObtainCurrent(thr, pc);
|
||||
rep.AddStack(&trace);
|
||||
OutputReport(CTX(), rep);
|
||||
}
|
||||
}
|
||||
s->mtx.Unlock();
|
||||
|
|
|
|||
|
|
@ -278,6 +278,7 @@ void ScopedReport::AddMutex(const SyncVar *s) {
|
|||
ReportMutex *rm = new(mem) ReportMutex();
|
||||
rep_->mutexes.PushBack(rm);
|
||||
rm->id = s->uid;
|
||||
rm->addr = s->addr;
|
||||
rm->destroyed = false;
|
||||
rm->stack = 0;
|
||||
#ifndef TSAN_GO
|
||||
|
|
@ -294,6 +295,7 @@ void ScopedReport::AddMutex(u64 id) {
|
|||
ReportMutex *rm = new(mem) ReportMutex();
|
||||
rep_->mutexes.PushBack(rm);
|
||||
rm->id = id;
|
||||
rm->addr = 0;
|
||||
rm->destroyed = true;
|
||||
rm->stack = 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// RUN: %clangxx_tsan %s -o %t
|
||||
// RUN: TSAN_OPTIONS=detect_deadlocks=1 %t 2>&1 | FileCheck %s
|
||||
// RUN: TSAN_OPTIONS=detect_deadlocks=1 not %t 2>&1 | FileCheck %s
|
||||
#include <pthread.h>
|
||||
#undef NDEBUG
|
||||
#include <assert.h>
|
||||
|
|
@ -46,9 +46,11 @@ class LockTest {
|
|||
// CHECK: Expecting lock inversion: [[A1:0x[a-f0-9]*]] [[A2:0x[a-f0-9]*]]
|
||||
L(0); L(1); U(0); U(1);
|
||||
L(1); L(0); U(0); U(1);
|
||||
// CHECK: ThreadSanitizer: lock-order-inversion (potential deadlock)
|
||||
// CHECK-NEXT: path: [[A1]] => [[A2]] => [[A1]]
|
||||
// CHECK-NOT: ThreadSanitizer:
|
||||
// CHECK: WARNING: ThreadSanitizer: lock-order-inversion (potential deadlock)
|
||||
// CHECK: path: [[M1:M[0-9]+]] => [[M2:M[0-9]+]] => [[M1]]
|
||||
// CHECK: Mutex [[M1]] ([[A1]]) created at:
|
||||
// CHECK: Mutex [[M2]] ([[A2]]) created at:
|
||||
// CHECK-NOT: WARNING: ThreadSanitizer:
|
||||
}
|
||||
|
||||
// Simple lock order inversion with 3 locks.
|
||||
|
|
@ -57,8 +59,8 @@ class LockTest {
|
|||
// CHECK: Starting Test2
|
||||
L(0); L(1); L(2); U(2); U(0); U(1);
|
||||
L(2); L(0); U(0); U(2);
|
||||
// CHECK: ThreadSanitizer: lock-order-inversion (potential deadlock)
|
||||
// CHECK-NOT: ThreadSanitizer:
|
||||
// CHECK: WARNING: ThreadSanitizer: lock-order-inversion (potential deadlock)
|
||||
// CHECK-NOT: WARNING: ThreadSanitizer:
|
||||
}
|
||||
|
||||
// Lock order inversion with lots of new locks created (but not used)
|
||||
|
|
@ -72,8 +74,8 @@ class LockTest {
|
|||
CreateAndDestroyManyLocks();
|
||||
U(2);
|
||||
L(1); L(0); U(0); U(1);
|
||||
// CHECK: ThreadSanitizer: lock-order-inversion (potential deadlock)
|
||||
// CHECK-NOT: ThreadSanitizer:
|
||||
// CHECK: WARNING: ThreadSanitizer: lock-order-inversion (potential deadlock)
|
||||
// CHECK-NOT: WARNING: ThreadSanitizer:
|
||||
}
|
||||
|
||||
// lock l0=>l1; then create and use lots of locks; then lock l1=>l0.
|
||||
|
|
@ -86,7 +88,7 @@ class LockTest {
|
|||
CreateLockUnlockAndDestroyManyLocks();
|
||||
U(2);
|
||||
L(1); L(0); U(0); U(1);
|
||||
// CHECK-NOT: ThreadSanitizer:
|
||||
// CHECK-NOT: WARNING: ThreadSanitizer:
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// RUN: %clangxx_tsan %s -o %t
|
||||
// RUN: TSAN_OPTIONS=detect_deadlocks=1 %t 2>&1 | FileCheck %s
|
||||
// RUN: TSAN_OPTIONS=detect_deadlocks=1 not %t 2>&1 | FileCheck %s
|
||||
#include <pthread.h>
|
||||
|
||||
int main() {
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ int main() {
|
|||
// CHECK: Write of size 4 at {{.*}} by thread T1
|
||||
// CHECK: (mutexes: write [[M1:M[0-9]+]]):
|
||||
// CHECK: Previous write of size 4 at {{.*}} by thread T2:
|
||||
// CHECK: Mutex [[M1]] created at:
|
||||
// CHECK: Mutex [[M1]] (0x{{.*}}) created at:
|
||||
// CHECK: #0 pthread_mutex_init
|
||||
// CHECK: #1 main {{.*}}/mutexset1.cc:[[@LINE+1]]
|
||||
pthread_mutex_init(&mtx, 0);
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ int main() {
|
|||
// CHECK: Write of size 4 at {{.*}} by thread T2:
|
||||
// CHECK: Previous write of size 4 at {{.*}} by thread T1
|
||||
// CHECK: (mutexes: write [[M1:M[0-9]+]]):
|
||||
// CHECK: Mutex [[M1]] created at:
|
||||
// CHECK: Mutex [[M1]] (0x{{.*}}) created at:
|
||||
// CHECK: #0 pthread_mutex_init
|
||||
// CHECK: #1 main {{.*}}/mutexset2.cc:[[@LINE+1]]
|
||||
pthread_mutex_init(&mtx, 0);
|
||||
|
|
|
|||
|
|
@ -27,10 +27,10 @@ int main() {
|
|||
// CHECK: Write of size 4 at {{.*}} by thread T1
|
||||
// CHECK: (mutexes: write [[M1:M[0-9]+]], write [[M2:M[0-9]+]]):
|
||||
// CHECK: Previous write of size 4 at {{.*}} by thread T2:
|
||||
// CHECK: Mutex [[M1]] created at:
|
||||
// CHECK: Mutex [[M1]] (0x{{.*}}) created at:
|
||||
// CHECK: #0 pthread_mutex_init
|
||||
// CHECK: #1 main {{.*}}/mutexset3.cc:[[@LINE+4]]
|
||||
// CHECK: Mutex [[M2]] created at:
|
||||
// CHECK: Mutex [[M2]] (0x{{.*}}) created at:
|
||||
// CHECK: #0 pthread_mutex_init
|
||||
// CHECK: #1 main {{.*}}/mutexset3.cc:[[@LINE+2]]
|
||||
pthread_mutex_init(&mtx1, 0);
|
||||
|
|
|
|||
|
|
@ -27,10 +27,10 @@ int main() {
|
|||
// CHECK: Write of size 4 at {{.*}} by thread T2:
|
||||
// CHECK: Previous write of size 4 at {{.*}} by thread T1
|
||||
// CHECK: (mutexes: write [[M1:M[0-9]+]], write [[M2:M[0-9]+]]):
|
||||
// CHECK: Mutex [[M1]] created at:
|
||||
// CHECK: Mutex [[M1]] (0x{{.*}}) created at:
|
||||
// CHECK: #0 pthread_mutex_init
|
||||
// CHECK: #1 main {{.*}}/mutexset4.cc:[[@LINE+4]]
|
||||
// CHECK: Mutex [[M2]] created at:
|
||||
// CHECK: Mutex [[M2]] (0x{{.*}}) created at:
|
||||
// CHECK: #0 pthread_mutex_init
|
||||
// CHECK: #1 main {{.*}}/mutexset4.cc:[[@LINE+2]]
|
||||
pthread_mutex_init(&mtx1, 0);
|
||||
|
|
|
|||
|
|
@ -28,10 +28,10 @@ int main() {
|
|||
// CHECK: (mutexes: write [[M1:M[0-9]+]]):
|
||||
// CHECK: Previous write of size 4 at {{.*}} by thread T2
|
||||
// CHECK: (mutexes: write [[M2:M[0-9]+]]):
|
||||
// CHECK: Mutex [[M1]] created at:
|
||||
// CHECK: Mutex [[M1]] (0x{{.*}}) created at:
|
||||
// CHECK: #0 pthread_mutex_init
|
||||
// CHECK: #1 main {{.*}}/mutexset5.cc:[[@LINE+4]]
|
||||
// CHECK: Mutex [[M2]] created at:
|
||||
// CHECK: Mutex [[M2]] (0x{{.*}}) created at:
|
||||
// CHECK: #0 pthread_mutex_init
|
||||
// CHECK: #1 main {{.*}}/mutexset5.cc:[[@LINE+5]]
|
||||
pthread_mutex_init(&mtx1, 0);
|
||||
|
|
|
|||
|
|
@ -33,11 +33,11 @@ int main() {
|
|||
// CHECK: (mutexes: write [[M1:M[0-9]+]]):
|
||||
// CHECK: Previous write of size 4 at {{.*}} by thread T2
|
||||
// CHECK: (mutexes: write [[M2:M[0-9]+]], read [[M3:M[0-9]+]]):
|
||||
// CHECK: Mutex [[M1]] created at:
|
||||
// CHECK: Mutex [[M1]] (0x{{.*}}) created at:
|
||||
// CHECK: #1 main {{.*}}/mutexset6.cc:[[@LINE+5]]
|
||||
// CHECK: Mutex [[M2]] created at:
|
||||
// CHECK: Mutex [[M2]] (0x{{.*}}) created at:
|
||||
// CHECK: #1 main {{.*}}/mutexset6.cc:[[@LINE+4]]
|
||||
// CHECK: Mutex [[M3]] created at:
|
||||
// CHECK: Mutex [[M3]] (0x{{.*}}) created at:
|
||||
// CHECK: #1 main {{.*}}/mutexset6.cc:[[@LINE+3]]
|
||||
pthread_mutex_init(&mtx1, 0);
|
||||
pthread_spin_init(&mtx2, 0);
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ int main() {
|
|||
// CHECK: Write of size 4 at {{.*}} by thread T1
|
||||
// CHECK: (mutexes: write [[M1:M[0-9]+]]):
|
||||
// CHECK: Previous write of size 4 at {{.*}} by thread T2:
|
||||
// CHECK: Mutex [[M1]] created at:
|
||||
// CHECK: Mutex [[M1]] (0x{{.*}}) created at:
|
||||
// CHECK: #0 pthread_mutex_init
|
||||
// CHECK: #1 main {{.*}}/mutexset8.cc
|
||||
mtx = new pthread_mutex_t;
|
||||
|
|
|
|||
Loading…
Reference in New Issue