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

llvm-svn: 162022
This commit is contained in:
Dmitry Vyukov 2012-08-16 15:08:49 +00:00
parent 19ae9f3b2e
commit 3482ec3bc8
7 changed files with 50 additions and 3 deletions

View File

@ -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

View File

@ -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);

View File

@ -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) {

View File

@ -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();
}

View File

@ -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;

View File

@ -21,6 +21,7 @@ SyncVar::SyncVar(uptr addr)
: mtx(MutexTypeSyncVar, StatMtxSyncVar)
, addr(addr)
, owner_tid(kInvalidTid)
, last_lock()
, recursion()
, is_rw()
, is_recursive()

View File

@ -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;