[compiler-rt] 82de586 - tsan: intercept clone

Dmitry Vyukov via llvm-commits llvm-commits at lists.llvm.org
Thu Nov 11 09:55:59 PST 2021


Author: Dmitry Vyukov
Date: 2021-11-11T18:55:54+01:00
New Revision: 82de586d4bd7c6a97f5bd30f1eaaa2e326c31612

URL: https://github.com/llvm/llvm-project/commit/82de586d4bd7c6a97f5bd30f1eaaa2e326c31612
DIFF: https://github.com/llvm/llvm-project/commit/82de586d4bd7c6a97f5bd30f1eaaa2e326c31612.diff

LOG: tsan: intercept clone

gtest uses clone for death tests and it needs the same
handling as fork to prevent deadlock (take runtime mutexes
before and release them after).

Reviewed By: melver

Differential Revision: https://reviews.llvm.org/D113677

Added: 
    compiler-rt/test/tsan/clone_deadlock.cpp

Modified: 
    compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp

Removed: 
    


################################################################################
diff  --git a/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp b/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp
index 617eda6503175..a712a3ad5bd9c 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp
+++ b/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp
@@ -2210,6 +2210,30 @@ TSAN_INTERCEPTOR(int, vfork, int fake) {
   return WRAP(fork)(fake);
 }
 
+TSAN_INTERCEPTOR(int, clone, int (*fn)(void *), void *stack, int flags,
+                 void *arg, int *parent_tid, void *tls, pid_t *child_tid) {
+  SCOPED_INTERCEPTOR_RAW(clone, fn, stack, flags, arg, parent_tid, tls,
+                         child_tid);
+  struct Arg {
+    int (*fn)(void *);
+    void *arg;
+  };
+  auto wrapper = +[](void *p) -> int {
+    auto *thr = cur_thread();
+    uptr pc = GET_CURRENT_PC();
+    ForkChildAfter(thr, pc);
+    FdOnFork(thr, pc);
+    auto *arg = static_cast<Arg *>(p);
+    return arg->fn(arg->arg);
+  };
+  ForkBefore(thr, pc);
+  Arg arg_wrapper = {fn, arg};
+  int pid = REAL(clone)(wrapper, stack, flags, &arg_wrapper, parent_tid, tls,
+                        child_tid);
+  ForkParentAfter(thr, pc);
+  return pid;
+}
+
 #if !SANITIZER_MAC && !SANITIZER_ANDROID
 typedef int (*dl_iterate_phdr_cb_t)(__sanitizer_dl_phdr_info *info, SIZE_T size,
                                     void *data);
@@ -2841,6 +2865,7 @@ void InitializeInterceptors() {
 
   TSAN_INTERCEPT(fork);
   TSAN_INTERCEPT(vfork);
+  TSAN_INTERCEPT(clone);
 #if !SANITIZER_ANDROID
   TSAN_INTERCEPT(dl_iterate_phdr);
 #endif

diff  --git a/compiler-rt/test/tsan/clone_deadlock.cpp b/compiler-rt/test/tsan/clone_deadlock.cpp
new file mode 100644
index 0000000000000..317ccdabdb704
--- /dev/null
+++ b/compiler-rt/test/tsan/clone_deadlock.cpp
@@ -0,0 +1,40 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %env_tsan_opts=atexit_sleep_ms=0 %run %t 2>&1 | FileCheck %s
+#include "test.h"
+#include <errno.h>
+#include <sched.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+long counter;
+
+static void *incrementer(void *arg) {
+  for (;;)
+    __sync_fetch_and_add(&counter, 1);
+  return 0;
+}
+
+static int cloned(void *arg) {
+  for (int i = 0; i < 1000; i++)
+    __sync_fetch_and_add(&counter, 1);
+  exit(0);
+  return 0;
+}
+
+int main() {
+  barrier_init(&barrier, 2);
+  pthread_t th;
+  pthread_create(&th, 0, incrementer, 0);
+  for (int i = 0; i < 100; i++) {
+    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);
+    }
+    while (wait(0) != pid) {
+    }
+  }
+  fprintf(stderr, "DONE\n");
+}
+
+// CHECK: DONE


        


More information about the llvm-commits mailing list