Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions compiler-rt/include/sanitizer/tsan_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,10 @@ void __tsan_mutex_post_signal(void *addr, unsigned flags);
void __tsan_mutex_pre_divert(void *addr, unsigned flags);
void __tsan_mutex_post_divert(void *addr, unsigned flags);

// Annotate that no mutexes can be held. If we are holding mutexes, then
// TSan will print a bug report.
void __tsan_check_no_mutexes_held();

// External race detection API.
// Can be used by non-instrumented libraries to detect when their objects are
// being used in an unsafe manner.
Expand Down
1 change: 1 addition & 0 deletions compiler-rt/lib/tsan/rtl/tsan.syms.extra
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ __tsan_mutex_pre_signal
__tsan_mutex_post_signal
__tsan_mutex_pre_divert
__tsan_mutex_post_divert
__tsan_check_no_mutexes_held
__tsan_get_current_fiber
__tsan_create_fiber
__tsan_destroy_fiber
Expand Down
4 changes: 3 additions & 1 deletion compiler-rt/lib/tsan/rtl/tsan_debugging.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ static const char *ReportTypeDescription(ReportType typ) {
case ReportTypeSignalUnsafe: return "signal-unsafe-call";
case ReportTypeErrnoInSignal: return "errno-in-signal-handler";
case ReportTypeDeadlock: return "lock-order-inversion";
// No default case so compiler warns us if we miss one
case ReportTypeMutexCannotBeLocked:
return "mutex-cannot-be-locked";
// No default case so compiler warns us if we miss one
}
UNREACHABLE("missing case");
}
Expand Down
22 changes: 22 additions & 0 deletions compiler-rt/lib/tsan/rtl/tsan_interface_ann.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -435,4 +435,26 @@ void __tsan_mutex_post_divert(void *addr, unsigned flagz) {
ThreadIgnoreBegin(thr, 0);
ThreadIgnoreSyncBegin(thr, 0);
}

static void ReportMutexCannotBeLocked(ThreadState *thr, uptr pc) {
ThreadRegistryLock l(&ctx->thread_registry);
ScopedReport rep(ReportTypeMutexCannotBeLocked);
for (uptr i = 0; i < thr->mset.Size(); ++i) {
MutexSet::Desc desc = thr->mset.Get(i);
rep.AddMutex(desc.addr, desc.stack_id);
}
VarSizeStackTrace trace;
ObtainCurrentStack(thr, pc, &trace);
rep.AddStack(trace, true);
OutputReport(thr, rep);
}

INTERFACE_ATTRIBUTE
void __tsan_check_no_mutexes_held() {
SCOPED_ANNOTATION(__tsan_check_no_mutexes_held);
if (thr->mset.Size() == 0) {
return;
}
ReportMutexCannotBeLocked(thr, pc);
}
} // extern "C"
17 changes: 12 additions & 5 deletions compiler-rt/lib/tsan/rtl/tsan_report.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,9 @@ static const char *ReportTypeString(ReportType typ, uptr tag) {
return "signal handler spoils errno";
case ReportTypeDeadlock:
return "lock-order-inversion (potential deadlock)";
// No default case so compiler warns us if we miss one
case ReportTypeMutexCannotBeLocked:
return "mutex cannot be locked on this code path";
// No default case so compiler warns us if we miss one
}
UNREACHABLE("missing case");
}
Expand Down Expand Up @@ -216,11 +218,16 @@ static void PrintMutexShortWithAddress(const ReportMutex *rm,
reinterpret_cast<void *>(rm->addr), d.Default(), after);
}

static void PrintMutex(const ReportMutex *rm) {
static void PrintMutex(const ReportMutex *rm, ReportType typ) {
Decorator d;
Printf("%s", d.Mutex());
Printf(" Mutex M%u (%p) created at:\n", rm->id,
reinterpret_cast<void *>(rm->addr));
if (typ != ReportTypeMutexCannotBeLocked) {
Printf(" Mutex M%u (%p) created at:\n", rm->id,
reinterpret_cast<void *>(rm->addr));
} else {
Printf(" Mutex M%u (%p) acquired at:\n", rm->id,
reinterpret_cast<void *>(rm->addr));
}
Printf("%s", d.Default());
PrintStack(rm->stack);
}
Expand Down Expand Up @@ -354,7 +361,7 @@ void PrintReport(const ReportDesc *rep) {

if (rep->typ != ReportTypeDeadlock) {
for (uptr i = 0; i < rep->mutexes.Size(); i++)
PrintMutex(rep->mutexes[i]);
PrintMutex(rep->mutexes[i], rep->typ);
}

for (uptr i = 0; i < rep->threads.Size(); i++)
Expand Down
3 changes: 2 additions & 1 deletion compiler-rt/lib/tsan/rtl/tsan_report.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ enum ReportType {
ReportTypeMutexBadReadUnlock,
ReportTypeSignalUnsafe,
ReportTypeErrnoInSignal,
ReportTypeDeadlock
ReportTypeDeadlock,
ReportTypeMutexCannotBeLocked
};

struct ReportStack {
Expand Down
1 change: 1 addition & 0 deletions compiler-rt/lib/tsan/rtl/tsan_suppressions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ static const char *conv(ReportType typ) {
case ReportTypeMutexBadUnlock:
case ReportTypeMutexBadReadLock:
case ReportTypeMutexBadReadUnlock:
case ReportTypeMutexCannotBeLocked:
return kSuppressionMutex;
case ReportTypeSignalUnsafe:
case ReportTypeErrnoInSignal:
Expand Down
24 changes: 24 additions & 0 deletions compiler-rt/test/tsan/mutex_cannot_be_locked.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
#include "test.h"

pthread_mutex_t mtx;

void *ThreadFunc(void *) {
pthread_mutex_lock(&mtx);
__tsan_check_no_mutexes_held();
}

int main() {
pthread_t th;
pthread_create(&th, 0, ThreadFunc, NULL);
pthread_join(th, 0);
return 0;
}

// CHECK: WARNING: ThreadSanitizer: mutex cannot be locked on this code path
// CHECK: #0 __tsan_check_no_mutexes_held
// CHECK: #1 ThreadFunc
// CHECK: Mutex {{.*}} acquired at:
// CHECK: #0 pthread_mutex_lock
// CHECK: #1 ThreadFunc
// CHECK: SUMMARY: ThreadSanitizer: mutex cannot be locked on this code path {{.*}}mutex_cannot_be_locked.cpp{{.*}}ThreadFunc
19 changes: 19 additions & 0 deletions compiler-rt/test/tsan/mutex_cannot_be_locked_success.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s
#include "test.h"

pthread_mutex_t mtx;

void *ThreadFunc(void *) {
pthread_mutex_lock(&mtx);
pthread_mutex_unlock(&mtx);
__tsan_check_no_mutexes_held();
}

int main() {
pthread_t th;
pthread_create(&th, 0, ThreadFunc, NULL);
pthread_join(th, 0);
return 0;
}

// CHECK-NOT: WARNING: ThreadSanitizer: mutex cannot be locked on this code path