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