1diff --git a/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp b/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp 2--- a/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp 3+++ b/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp 4@@ -1976,7 +1976,8 @@ 5 // because in async signal processing case (when handler is called directly 6 // from rtl_generic_sighandler) we have not yet received the reraised 7 // signal; and it looks too fragile to intercept all ways to reraise a signal. 8- if (flags()->report_bugs && !sync && sig != SIGTERM && errno != 99) { 9+ if (ShouldReport(thr, ReportTypeErrnoInSignal) && !sync && sig != SIGTERM && 10+ errno != 99) { 11 VarSizeStackTrace stack; 12 // StackTrace::GetNestInstructionPc(pc) is used because return address is 13 // expected, OutputReport() will undo this. 14diff --git a/compiler-rt/lib/tsan/rtl/tsan_mman.cpp b/compiler-rt/lib/tsan/rtl/tsan_mman.cpp 15--- a/compiler-rt/lib/tsan/rtl/tsan_mman.cpp 16+++ b/compiler-rt/lib/tsan/rtl/tsan_mman.cpp 17@@ -145,7 +145,7 @@ 18 19 static void SignalUnsafeCall(ThreadState *thr, uptr pc) { 20 if (atomic_load_relaxed(&thr->in_signal_handler) == 0 || 21- !flags()->report_signal_unsafe) 22+ !ShouldReport(thr, ReportTypeSignalUnsafe)) 23 return; 24 VarSizeStackTrace stack; 25 ObtainCurrentStack(thr, pc, &stack); 26diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl.h b/compiler-rt/lib/tsan/rtl/tsan_rtl.h 27--- a/compiler-rt/lib/tsan/rtl/tsan_rtl.h 28+++ b/compiler-rt/lib/tsan/rtl/tsan_rtl.h 29@@ -624,6 +624,7 @@ 30 ScopedErrorReportLock lock_; 31 }; 32 33+bool ShouldReport(ThreadState *thr, ReportType typ); 34 ThreadContext *IsThreadStackOrTls(uptr addr, bool *is_stack); 35 void RestoreStack(int tid, const u64 epoch, VarSizeStackTrace *stk, 36 MutexSet *mset, uptr *tag = nullptr); 37diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp b/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp 38--- a/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp 39+++ b/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp 40@@ -519,23 +519,22 @@ 41 void ForkBefore(ThreadState *thr, uptr pc) { 42 ctx->thread_registry->Lock(); 43 ctx->report_mtx.Lock(); 44- // Ignore memory accesses in the pthread_atfork callbacks. 45- // If any of them triggers a data race we will deadlock 46- // on the report_mtx. 47+ // Suppress all reports in the pthread_atfork callbacks. 48+ // Reports will deadlock on the report_mtx. 49 // We could ignore interceptors and sync operations as well, 50 // but so far it's unclear if it will do more good or harm. 51 // Unnecessarily ignoring things can lead to false positives later. 52- ThreadIgnoreBegin(thr, pc); 53+ thr->suppress_reports++; 54 } 55 56 void ForkParentAfter(ThreadState *thr, uptr pc) { 57- ThreadIgnoreEnd(thr, pc); // Begin is in ForkBefore. 58+ thr->suppress_reports--; // Enabled in ForkBefore. 59 ctx->report_mtx.Unlock(); 60 ctx->thread_registry->Unlock(); 61 } 62 63 void ForkChildAfter(ThreadState *thr, uptr pc) { 64- ThreadIgnoreEnd(thr, pc); // Begin is in ForkBefore. 65+ thr->suppress_reports--; // Enabled in ForkBefore. 66 ctx->report_mtx.Unlock(); 67 ctx->thread_registry->Unlock(); 68 69diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cpp b/compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cpp 70--- a/compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cpp 71+++ b/compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cpp 72@@ -51,6 +51,8 @@ 73 // or false positives (e.g. unlock in a different thread). 74 if (SANITIZER_GO) 75 return; 76+ if (!ShouldReport(thr, typ)) 77+ return; 78 ThreadRegistryLock l(ctx->thread_registry); 79 ScopedReport rep(typ); 80 rep.AddMutex(mid); 81@@ -107,7 +109,7 @@ 82 if (!unlock_locked) 83 s->Reset(thr->proc()); // must not reset it before the report is printed 84 s->mtx.Unlock(); 85- if (unlock_locked) { 86+ if (unlock_locked && ShouldReport(thr, ReportTypeMutexDestroyLocked)) { 87 ThreadRegistryLock l(ctx->thread_registry); 88 ScopedReport rep(ReportTypeMutexDestroyLocked); 89 rep.AddMutex(mid); 90@@ -534,7 +536,7 @@ 91 } 92 93 void ReportDeadlock(ThreadState *thr, uptr pc, DDReport *r) { 94- if (r == 0) 95+ if (r == 0 || !ShouldReport(thr, ReportTypeDeadlock)) 96 return; 97 ThreadRegistryLock l(ctx->thread_registry); 98 ScopedReport rep(ReportTypeDeadlock); 99diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cpp b/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cpp 100--- a/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cpp 101+++ b/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cpp 102@@ -142,6 +142,27 @@ 103 return stack; 104 } 105 106+bool ShouldReport(ThreadState *thr, ReportType typ) { 107+ // We set thr->suppress_reports in the fork context. 108+ // Taking any locking in the fork context can lead to deadlocks. 109+ // If any locks are already taken, it's too late to do this check. 110+ CheckNoLocks(thr); 111+ if (SANITIZER_DEBUG) 112+ ThreadRegistryLock l(ctx->thread_registry); 113+ if (!flags()->report_bugs || thr->suppress_reports) 114+ return false; 115+ switch (typ) { 116+ case ReportTypeSignalUnsafe: 117+ return flags()->report_signal_unsafe; 118+ case ReportTypeThreadLeak: 119+ return flags()->report_thread_leaks; 120+ case ReportTypeMutexDestroyLocked: 121+ return flags()->report_destroy_locked; 122+ default: 123+ return true; 124+ } 125+} 126+ 127 ScopedReportBase::ScopedReportBase(ReportType typ, uptr tag) { 128 ctx->thread_registry->CheckLocked(); 129 void *mem = internal_alloc(MBlockReport, sizeof(ReportDesc)); 130@@ -497,8 +518,10 @@ 131 } 132 133 bool OutputReport(ThreadState *thr, const ScopedReport &srep) { 134- if (!flags()->report_bugs || thr->suppress_reports) 135- return false; 136+ // These should have been checked in ShouldReport. 137+ // It's too late to check them here, we have already taken locks. 138+ CHECK(flags()->report_bugs); 139+ CHECK(!thr->suppress_reports); 140 atomic_store_relaxed(&ctx->last_symbolize_time_ns, NanoTime()); 141 const ReportDesc *rep = srep.GetReport(); 142 CHECK_EQ(thr->current_report, nullptr); 143@@ -589,7 +612,7 @@ 144 // at best it will cause deadlocks on internal mutexes. 145 ScopedIgnoreInterceptors ignore; 146 147- if (!flags()->report_bugs) 148+ if (!ShouldReport(thr, ReportTypeRace)) 149 return; 150 if (!flags()->report_atomic_races && !RaceBetweenAtomicAndFree(thr)) 151 return; 152diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cpp b/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cpp 153--- a/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cpp 154+++ b/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cpp 155@@ -210,7 +210,7 @@ 156 void ThreadFinalize(ThreadState *thr) { 157 ThreadCheckIgnore(thr); 158 #if !SANITIZER_GO 159- if (!flags()->report_thread_leaks) 160+ if (!ShouldReport(thr, ReportTypeThreadLeak)) 161 return; 162 ThreadRegistryLock l(ctx->thread_registry); 163 Vector<ThreadLeak> leaks; 164diff --git a/compiler-rt/test/tsan/pthread_atfork_deadlock3.c b/compiler-rt/test/tsan/pthread_atfork_deadlock3.c 165new file mode 100644 166--- /dev/null 167+++ b/compiler-rt/test/tsan/pthread_atfork_deadlock3.c 168@@ -0,0 +1,71 @@ 169+// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s 170+// Regression test for 171+// https://groups.google.com/g/thread-sanitizer/c/TQrr4-9PRYo/m/HFR4FMi6AQAJ 172+#include "test.h" 173+#include <sys/types.h> 174+#include <sys/wait.h> 175+#include <errno.h> 176+#include <string.h> 177+#include <signal.h> 178+ 179+long glob = 0; 180+ 181+void *worker(void *main) { 182+ glob++; 183+ barrier_wait(&barrier); 184+ barrier_wait(&barrier); 185+ pthread_kill((pthread_t)main, SIGPROF); 186+ barrier_wait(&barrier); 187+ return NULL; 188+} 189+ 190+void atfork() { 191+ barrier_wait(&barrier); 192+ barrier_wait(&barrier); 193+ write(2, "in atfork\n", strlen("in atfork\n")); 194+ static volatile long a; 195+ __atomic_fetch_add(&a, 1, __ATOMIC_RELEASE); 196+} 197+ 198+void handler(int sig) { 199+ write(2, "in handler\n", strlen("in handler\n")); 200+ glob++; 201+} 202+ 203+int main() { 204+ barrier_init(&barrier, 2); 205+ struct sigaction act = {}; 206+ act.sa_handler = &handler; 207+ if (sigaction(SIGPROF, &act, 0)) { 208+ perror("sigaction"); 209+ exit(1); 210+ } 211+ pthread_atfork(atfork, NULL, NULL); 212+ pthread_t t; 213+ pthread_create(&t, NULL, worker, (void*)pthread_self()); 214+ barrier_wait(&barrier); 215+ pid_t pid = fork(); 216+ if (pid < 0) { 217+ fprintf(stderr, "fork failed: %d\n", errno); 218+ return 1; 219+ } 220+ if (pid == 0) { 221+ fprintf(stderr, "CHILD\n"); 222+ return 0; 223+ } 224+ if (pid != waitpid(pid, NULL, 0)) { 225+ fprintf(stderr, "waitpid failed: %d\n", errno); 226+ return 1; 227+ } 228+ pthread_join(t, NULL); 229+ fprintf(stderr, "PARENT\n"); 230+ return 0; 231+} 232+ 233+// CHECK: in atfork 234+// CHECK: in handler 235+// Note: There is a race, but we won't report it 236+// to not deadlock. 237+// CHECK-NOT: ThreadSanitizer: data race 238+// CHECK: CHILD 239+// CHECK: PARENT 240 241