forked from OSchip/llvm-project
tsan: better diagnostics for destroy of a locked mutex + a test
llvm-svn: 162022
This commit is contained in:
parent
19ae9f3b2e
commit
3482ec3bc8
|
@ -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
|
||||
|
|
@ -109,8 +109,11 @@ void PrintReport(const ReportDesc *rep) {
|
|||
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);
|
||||
|
|
|
@ -83,6 +83,10 @@ class FastState {
|
|||
: x_(x) {
|
||||
}
|
||||
|
||||
u64 raw() const {
|
||||
return x_;
|
||||
}
|
||||
|
||||
u64 tid() const {
|
||||
u64 res = x_ >> kTidShift;
|
||||
return res;
|
||||
|
@ -143,7 +147,6 @@ class Shadow : public FastState {
|
|||
}
|
||||
|
||||
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 @@ class ScopedReport {
|
|||
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) {
|
||||
|
|
|
@ -47,6 +47,12 @@ void MutexDestroy(ThreadState *thr, uptr pc, uptr addr) {
|
|||
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 @@ void MutexLock(ThreadState *thr, uptr pc, uptr addr) {
|
|||
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 @@ void MutexReadLock(ThreadState *thr, uptr pc, uptr addr) {
|
|||
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();
|
||||
}
|
||||
|
|
|
@ -188,7 +188,7 @@ const ReportDesc *ScopedReport::GetReport() const {
|
|||
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;
|
||||
|
|
|
@ -21,6 +21,7 @@ SyncVar::SyncVar(uptr addr)
|
|||
: mtx(MutexTypeSyncVar, StatMtxSyncVar)
|
||||
, addr(addr)
|
||||
, owner_tid(kInvalidTid)
|
||||
, last_lock()
|
||||
, recursion()
|
||||
, is_rw()
|
||||
, is_recursive()
|
||||
|
|
|
@ -60,6 +60,7 @@ struct SyncVar {
|
|||
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;
|
||||
|
|
Loading…
Reference in New Issue