[compiler-rt] e91595b - tsan: don't start background thread after clone
Dmitry Vyukov via llvm-commits
llvm-commits at lists.llvm.org
Fri Nov 12 03:58:52 PST 2021
Author: Dmitry Vyukov
Date: 2021-11-12T12:58:49+01:00
New Revision: e91595bf948a23bb44a47854321aa80307a48fd1
URL: https://github.com/llvm/llvm-project/commit/e91595bf948a23bb44a47854321aa80307a48fd1
DIFF: https://github.com/llvm/llvm-project/commit/e91595bf948a23bb44a47854321aa80307a48fd1.diff
LOG: tsan: don't start background thread after clone
Start the background thread only after fork, but not after clone.
For fork we did this always and it's known to work (or user code has adopted).
But if we do this for the new clone interceptor some code (sandbox2) fails.
So model we used to do for years and don't start the background thread after clone.
Reviewed By: melver
Differential Revision: https://reviews.llvm.org/D113744
Added:
compiler-rt/test/tsan/Linux/clone_setns.cpp
Modified:
compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp
compiler-rt/lib/tsan/rtl/tsan_rtl.cpp
compiler-rt/lib/tsan/rtl/tsan_rtl.h
Removed:
################################################################################
diff --git a/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp b/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp
index c7dcd07b8529..9a85ee00d2d7 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp
+++ b/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp
@@ -2189,7 +2189,7 @@ void atfork_child() {
return;
ThreadState *thr = cur_thread();
const uptr pc = StackTrace::GetCurrentPc();
- ForkChildAfter(thr, pc);
+ ForkChildAfter(thr, pc, true);
FdOnFork(thr, pc);
}
@@ -2222,7 +2222,12 @@ TSAN_INTERCEPTOR(int, clone, int (*fn)(void *), void *stack, int flags,
auto wrapper = +[](void *p) -> int {
auto *thr = cur_thread();
uptr pc = GET_CURRENT_PC();
- ForkChildAfter(thr, pc);
+ // Start the background thread for fork, but not for clone.
+ // For fork we did this always and it's known to work (or user code has
+ // adopted). But if we do this for the new clone interceptor some code
+ // (sandbox2) fails. So model we used to do for years and don't start the
+ // background thread after clone.
+ ForkChildAfter(thr, pc, false);
FdOnFork(thr, pc);
auto *arg = static_cast<Arg *>(p);
return arg->fn(arg->arg);
@@ -2570,7 +2575,7 @@ static void syscall_post_fork(uptr pc, int pid) {
ThreadState *thr = cur_thread();
if (pid == 0) {
// child
- ForkChildAfter(thr, pc);
+ ForkChildAfter(thr, pc, true);
FdOnFork(thr, pc);
} else if (pid > 0) {
// parent
diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp b/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp
index 6e57d4aeb093..46dec04b8759 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp
+++ b/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp
@@ -506,7 +506,8 @@ void ForkParentAfter(ThreadState *thr, uptr pc) NO_THREAD_SAFETY_ANALYSIS {
ctx->thread_registry.Unlock();
}
-void ForkChildAfter(ThreadState *thr, uptr pc) NO_THREAD_SAFETY_ANALYSIS {
+void ForkChildAfter(ThreadState *thr, uptr pc,
+ bool start_thread) NO_THREAD_SAFETY_ANALYSIS {
thr->suppress_reports--; // Enabled in ForkBefore.
thr->ignore_interceptors--;
ScopedErrorReportLock::Unlock();
@@ -518,7 +519,8 @@ void ForkChildAfter(ThreadState *thr, uptr pc) NO_THREAD_SAFETY_ANALYSIS {
VPrintf(1, "ThreadSanitizer: forked new process with pid %d,"
" parent had %d threads\n", (int)internal_getpid(), (int)nthread);
if (nthread == 1) {
- StartBackgroundThread();
+ if (start_thread)
+ StartBackgroundThread();
} else {
// We've just forked a multi-threaded process. We cannot reasonably function
// after that (some mutexes may be locked before fork). So just enable
diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl.h b/compiler-rt/lib/tsan/rtl/tsan_rtl.h
index 089144c17ff0..eab83704240d 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_rtl.h
+++ b/compiler-rt/lib/tsan/rtl/tsan_rtl.h
@@ -440,7 +440,7 @@ void InitializeDynamicAnnotations();
void ForkBefore(ThreadState *thr, uptr pc);
void ForkParentAfter(ThreadState *thr, uptr pc);
-void ForkChildAfter(ThreadState *thr, uptr pc);
+void ForkChildAfter(ThreadState *thr, uptr pc, bool start_thread);
void ReportRace(ThreadState *thr);
bool OutputReport(ThreadState *thr, const ScopedReport &srep);
diff --git a/compiler-rt/test/tsan/Linux/clone_setns.cpp b/compiler-rt/test/tsan/Linux/clone_setns.cpp
new file mode 100644
index 000000000000..25e30345cce9
--- /dev/null
+++ b/compiler-rt/test/tsan/Linux/clone_setns.cpp
@@ -0,0 +1,39 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+
+// The test models how sandbox2 unshares user namespace after clone:
+// https://github.com/google/sandboxed-api/blob/c95837a6c131fbdf820db352a97d54fcbcbde6c0/sandboxed_api/sandbox2/forkserver.cc#L249
+// which works only in sigle-threaded processes.
+
+#include "../test.h"
+#include <errno.h>
+#include <sched.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+static int cloned(void *arg) {
+ if (unshare(CLONE_NEWUSER)) {
+ fprintf(stderr, "unshare failed: %d\n", errno);
+ exit(1);
+ }
+ exit(0);
+ return 0;
+}
+
+int main() {
+ char stack[64 << 10] __attribute__((aligned(64)));
+ int pid = clone(cloned, stack + sizeof(stack), SIGCHLD, 0);
+ if (pid == -1) {
+ fprintf(stderr, "failed to clone: %d\n", errno);
+ exit(1);
+ }
+ int status = 0;
+ while (wait(&status) != pid) {
+ }
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+ fprintf(stderr, "child failed: %d\n", status);
+ exit(1);
+ }
+ fprintf(stderr, "DONE\n");
+}
+
+// CHECK: DONE
More information about the llvm-commits
mailing list