xref: /llvm-project/compiler-rt/test/tsan/Darwin/fork_deadlock.cpp (revision 804415825b97e974c96a92580bcbeaf4c7ff0a04)
1 // TODO(#96597): fix and reenable
2 // UNSUPPORTED: darwin
3 
4 // RUN: %clangxx_tsan -O1 %s -o %t && %env_tsan_opts=atexit_sleep_ms=0 %run %t 2>&1 | FileCheck %s
5 
6 // This test models what happens on Mac when fork
7 // calls malloc/free inside of our atfork callbacks.
8 // and ensures that we don't deadlock on malloc/free calls.
9 
10 #include "../test.h"
11 #include "syscall.h"
12 #include <errno.h>
13 #include <string.h>
14 #include <sys/types.h>
15 #include <sys/wait.h>
16 
17 // disable_sanitizer_instrumentation on __tsan_test_only_on_fork is not
18 // transitive, so we must apply it here as well.
19 // Instrumenting alloc_free_blocks() will result in deadlocks in TSan.
alloc_free_blocks()20 __attribute__((disable_sanitizer_instrumentation)) void alloc_free_blocks() {
21   // Allocate a bunch of blocks to drain local allocator cache
22   // and provoke it to lock allocator global mutexes.
23   const int kBlocks = 1000;
24   void *blocks[kBlocks];
25   for (int i = 0; i < kBlocks; i++) {
26     void *p = malloc(10);
27     *(volatile char *)p = 0;
28     blocks[i] = p;
29   }
30   for (int i = 0; i < kBlocks; i++)
31     free(blocks[i]);
32 }
33 
34 __attribute__((disable_sanitizer_instrumentation)) extern "C" void
__tsan_test_only_on_fork()35 __tsan_test_only_on_fork() {
36   const char *msg = "__tsan_test_only_on_fork\n";
37   write(2, msg, strlen(msg));
38   alloc_free_blocks();
39 }
40 
background(void * p)41 static void *background(void *p) {
42   for (;;)
43     alloc_free_blocks();
44   return 0;
45 }
46 
main()47 int main() {
48   pthread_t th;
49   pthread_create(&th, 0, background, 0);
50   pthread_detach(th);
51   for (int i = 0; i < 10; i++) {
52     int pid = myfork();
53     if (pid < 0) {
54       fprintf(stderr, "failed to fork (%d)\n", errno);
55       exit(1);
56     }
57     if (pid == 0) {
58       // child
59       exit(0);
60     }
61     // parent
62     while (wait(0) < 0) {
63     }
64   }
65   fprintf(stderr, "DONE\n");
66 }
67 
68 // CHECK: __tsan_test_only_on_fork
69 // CHECK: DONE
70