diff options
-rw-r--r-- | compiler-rt/lib/tsan/rtl/tsan_report.cc | 2 | ||||
-rw-r--r-- | compiler-rt/lib/tsan/rtl/tsan_report.h | 1 | ||||
-rw-r--r-- | compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cc | 27 | ||||
-rw-r--r-- | compiler-rt/test/tsan/mutex_bad_unlock.cc | 18 |
4 files changed, 37 insertions, 11 deletions
diff --git a/compiler-rt/lib/tsan/rtl/tsan_report.cc b/compiler-rt/lib/tsan/rtl/tsan_report.cc index b0ad670da3e..6875c4cad44 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_report.cc +++ b/compiler-rt/lib/tsan/rtl/tsan_report.cc @@ -76,6 +76,8 @@ static const char *ReportTypeString(ReportType typ) { return "destroy of a locked mutex"; if (typ == ReportTypeMutexDoubleLock) return "double lock of a mutex"; + if (typ == ReportTypeMutexBadUnlock) + return "unlock of an unlocked mutex (or by a wrong thread)"; if (typ == ReportTypeSignalUnsafe) return "signal-unsafe call inside of a signal"; if (typ == ReportTypeErrnoInSignal) diff --git a/compiler-rt/lib/tsan/rtl/tsan_report.h b/compiler-rt/lib/tsan/rtl/tsan_report.h index aaa562b5def..5b643351bce 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_report.h +++ b/compiler-rt/lib/tsan/rtl/tsan_report.h @@ -25,6 +25,7 @@ enum ReportType { ReportTypeThreadLeak, ReportTypeMutexDestroyLocked, ReportTypeMutexDoubleLock, + ReportTypeMutexBadUnlock, ReportTypeSignalUnsafe, ReportTypeErrnoInSignal, ReportTypeDeadlock diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cc b/compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cc index 83e76968b32..4f6a2d09bba 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cc +++ b/compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cc @@ -170,18 +170,11 @@ int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, bool all) { thr->fast_state.IncrementEpoch(); TraceAddEvent(thr, thr->fast_state, EventTypeUnlock, s->GetId()); int rec = 0; - if (s->recursion == 0) { - if (!s->is_broken) { - s->is_broken = true; - Printf("ThreadSanitizer WARNING: unlock of unlocked mutex %p\n", addr); - PrintCurrentStack(thr, pc); - } - } else if (s->owner_tid != thr->tid) { - if (!s->is_broken) { + bool report_bad_unlock = false; + if (s->recursion == 0 || s->owner_tid != thr->tid) { + if (flags()->report_mutex_bugs && !s->is_broken) { s->is_broken = true; - Printf("ThreadSanitizer WARNING: mutex %p is unlocked by wrong thread\n", - addr); - PrintCurrentStack(thr, pc); + report_bad_unlock = true; } } else { rec = all ? s->recursion : 1; @@ -199,7 +192,19 @@ int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, bool all) { Callback cb(thr, pc); ctx->dd->MutexBeforeUnlock(&cb, &s->dd, true); } + u64 mid = s->GetId(); s->mtx.Unlock(); + // Can't touch s after this point. + if (report_bad_unlock) { + ThreadRegistryLock l(ctx->thread_registry); + ScopedReport rep(ReportTypeMutexBadUnlock); + rep.AddMutex(mid); + StackTrace trace; + trace.ObtainCurrent(thr, pc); + rep.AddStack(&trace); + rep.AddLocation(addr, 1); + OutputReport(ctx, rep); + } if (flags()->detect_deadlocks) { Callback cb(thr, pc); ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb)); diff --git a/compiler-rt/test/tsan/mutex_bad_unlock.cc b/compiler-rt/test/tsan/mutex_bad_unlock.cc new file mode 100644 index 00000000000..dce815cafc5 --- /dev/null +++ b/compiler-rt/test/tsan/mutex_bad_unlock.cc @@ -0,0 +1,18 @@ +// RUN: %clangxx_tsan -O1 %s -o %t && not %t 2>&1 | FileCheck %s +extern "C" void AnnotateRWLockReleased(const char *f, int l, void *m, long rw); + +int main() { + int m = 0; + AnnotateRWLockReleased(__FILE__, __LINE__, &m, 1); + return 0; +} + +// CHECK: WARNING: ThreadSanitizer: unlock of an unlocked mutex (or by a wrong thread) +// CHECK: #0 AnnotateRWLockReleased +// CHECK: #1 main +// CHECK: Location is stack of main thread. +// CHECK: Mutex M1 ({{.*}}) created at: +// CHECK: #0 AnnotateRWLockReleased +// CHECK: #1 main +// CHECK: SUMMARY: ThreadSanitizer: unlock of an unlocked mutex (or by a wrong thread) + |