Index: lib/tsan/rtl/tsan_interceptors.cc =================================================================== --- lib/tsan/rtl/tsan_interceptors.cc +++ lib/tsan/rtl/tsan_interceptors.cc @@ -278,6 +278,7 @@ void ScopedInterceptor::EnableIgnores() { if (ignoring_) { ThreadIgnoreBegin(thr_, pc_, false); + if (flags()->ignore_noninstrumented_modules) thr_->suppress_reports++; if (in_ignored_lib_) { DCHECK(!thr_->in_ignored_lib); thr_->in_ignored_lib = true; @@ -288,6 +289,7 @@ void ScopedInterceptor::DisableIgnores() { if (ignoring_) { ThreadIgnoreEnd(thr_, pc_); + if (flags()->ignore_noninstrumented_modules) thr_->suppress_reports--; if (in_ignored_lib_) { DCHECK(thr_->in_ignored_lib); thr_->in_ignored_lib = false; Index: lib/tsan/rtl/tsan_rtl.h =================================================================== --- lib/tsan/rtl/tsan_rtl.h +++ lib/tsan/rtl/tsan_rtl.h @@ -381,6 +381,7 @@ // for better performance. int ignore_reads_and_writes; int ignore_sync; + int suppress_reports; // Go does not support ignores. #if !SANITIZER_GO IgnoreSet mop_ignore_set; Index: lib/tsan/rtl/tsan_rtl_report.cc =================================================================== --- lib/tsan/rtl/tsan_rtl_report.cc +++ lib/tsan/rtl/tsan_rtl_report.cc @@ -500,7 +500,7 @@ } bool OutputReport(ThreadState *thr, const ScopedReport &srep) { - if (!flags()->report_bugs) + if (!flags()->report_bugs || thr->suppress_reports) return false; atomic_store_relaxed(&ctx->last_symbolize_time_ns, NanoTime()); const ReportDesc *rep = srep.GetReport(); Index: test/tsan/Darwin/deadlock.mm =================================================================== --- test/tsan/Darwin/deadlock.mm +++ test/tsan/Darwin/deadlock.mm @@ -0,0 +1,47 @@ +// RUN: %clang_tsan %s -o %t -framework Foundation +// RUN: %deflake %run %t 2>&1 | FileCheck %s + +#import + +#import "../test.h" + +pthread_mutex_t m1; +pthread_mutex_t m2; + +int main(int argc, const char *argv[]) { + barrier_init(&barrier, 2); + fprintf(stderr, "Hello world.\n"); + + pthread_mutex_init(&m1, NULL); + pthread_mutex_init(&m2, NULL); + + [NSThread detachNewThreadWithBlock:^{ + pthread_mutex_lock(&m1); + pthread_mutex_lock(&m2); + pthread_mutex_unlock(&m2); + pthread_mutex_unlock(&m1); + + barrier_wait(&barrier); + }]; + [NSThread detachNewThreadWithBlock:^{ + barrier_wait(&barrier); + + pthread_mutex_lock(&m2); + pthread_mutex_lock(&m1); + pthread_mutex_unlock(&m1); + pthread_mutex_unlock(&m2); + + dispatch_sync(dispatch_get_main_queue(), ^{ + CFRunLoopStop(CFRunLoopGetCurrent()); + }); + }]; + + CFRunLoopRun(); + + fprintf(stderr, "Done.\n"); + return 0; +} + +// CHECK: Hello world. +// CHECK: WARNING: ThreadSanitizer: lock-order-inversion (potential deadlock) +// CHECK: Done.