[compiler-rt] 6a39582 - tsan: add another fork test
Dmitry Vyukov via llvm-commits
llvm-commits at lists.llvm.org
Sun Nov 21 23:36:55 PST 2021
Author: Dmitry Vyukov
Date: 2021-11-22T08:36:51+01:00
New Revision: 6a3958247aeeacdbf40833151220b089f066c82f
URL: https://github.com/llvm/llvm-project/commit/6a3958247aeeacdbf40833151220b089f066c82f
DIFF: https://github.com/llvm/llvm-project/commit/6a3958247aeeacdbf40833151220b089f066c82f.diff
LOG: tsan: add another fork test
Add a fork test that models what happens on Mac
where fork calls malloc/free inside of our atfork
callbacks.
Reviewed By: vitalybuka, yln
Differential Revision: https://reviews.llvm.org/D114250
Added:
compiler-rt/test/tsan/Linux/fork_deadlock.cpp
Modified:
compiler-rt/lib/tsan/rtl/tsan_rtl.cpp
Removed:
################################################################################
diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp b/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp
index ff7726ef06087..8126a503ff6dc 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp
+++ b/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp
@@ -34,6 +34,9 @@ extern "C" void __tsan_resume() {
__tsan_resumed = 1;
}
+SANITIZER_WEAK_DEFAULT_IMPL
+void __tsan_test_only_on_fork() {}
+
namespace __tsan {
#if !SANITIZER_GO
@@ -499,7 +502,11 @@ void ForkBefore(ThreadState *thr, uptr pc) NO_THREAD_SAFETY_ANALYSIS {
thr->suppress_reports++;
// On OS X, REAL(fork) can call intercepted functions (OSSpinLockLock), and
// we'll assert in CheckNoLocks() unless we ignore interceptors.
+ // On OS X libSystem_atfork_prepare/parent/child callbacks are called
+ // after/before our callbacks and they call free.
thr->ignore_interceptors++;
+
+ __tsan_test_only_on_fork();
}
void ForkParentAfter(ThreadState *thr, uptr pc) NO_THREAD_SAFETY_ANALYSIS {
diff --git a/compiler-rt/test/tsan/Linux/fork_deadlock.cpp b/compiler-rt/test/tsan/Linux/fork_deadlock.cpp
new file mode 100644
index 0000000000000..8f38ab92e69f6
--- /dev/null
+++ b/compiler-rt/test/tsan/Linux/fork_deadlock.cpp
@@ -0,0 +1,63 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %env_tsan_opts=atexit_sleep_ms=0 %run %t 2>&1 | FileCheck %s
+
+// This test models what happens on Mac when fork
+// calls malloc/free inside of our atfork callbacks.
+// and ensures that we don't deadlock on malloc/free calls.
+
+#include "../test.h"
+#include "syscall.h"
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+void alloc_free_blocks() {
+ // Allocate a bunch of blocks to drain local allocator cache
+ // and provoke it to lock allocator global mutexes.
+ const int kBlocks = 1000;
+ void *blocks[kBlocks];
+ for (int i = 0; i < kBlocks; i++) {
+ void *p = malloc(10);
+ *(volatile char *)p = 0;
+ blocks[i] = p;
+ }
+ for (int i = 0; i < kBlocks; i++)
+ free(blocks[i]);
+}
+
+__attribute__((disable_sanitizer_instrumentation)) extern "C" void
+__tsan_test_only_on_fork() {
+ const char *msg = "__tsan_test_only_on_fork\n";
+ write(2, msg, strlen(msg));
+ alloc_free_blocks();
+}
+
+static void *background(void *p) {
+ for (;;)
+ alloc_free_blocks();
+ return 0;
+}
+
+int main() {
+ pthread_t th;
+ pthread_create(&th, 0, background, 0);
+ pthread_detach(th);
+ for (int i = 0; i < 10; i++) {
+ int pid = myfork();
+ if (pid < 0) {
+ fprintf(stderr, "failed to fork (%d)\n", errno);
+ exit(1);
+ }
+ if (pid == 0) {
+ // child
+ exit(0);
+ }
+ // parent
+ while (wait(0) < 0) {
+ }
+ }
+ fprintf(stderr, "DONE\n");
+}
+
+// CHECK: __tsan_test_only_on_fork
+// CHECK: DONE
More information about the llvm-commits
mailing list