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