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 // disable_sanitizer_instrumentation on __tsan_test_only_on_fork is not 15 // transitive, so we must apply it here as well. 16 // Instrumenting alloc_free_blocks() will result in deadlocks in TSan. alloc_free_blocks()17__attribute__((disable_sanitizer_instrumentation)) void alloc_free_blocks() { 18 // Allocate a bunch of blocks to drain local allocator cache 19 // and provoke it to lock allocator global mutexes. 20 const int kBlocks = 1000; 21 void *blocks[kBlocks]; 22 for (int i = 0; i < kBlocks; i++) { 23 void *p = malloc(10); 24 *(volatile char *)p = 0; 25 blocks[i] = p; 26 } 27 for (int i = 0; i < kBlocks; i++) 28 free(blocks[i]); 29 } 30 31 __attribute__((disable_sanitizer_instrumentation)) extern "C" void __tsan_test_only_on_fork()32__tsan_test_only_on_fork() { 33 const char *msg = "__tsan_test_only_on_fork\n"; 34 write(2, msg, strlen(msg)); 35 alloc_free_blocks(); 36 } 37 background(void * p)38static void *background(void *p) { 39 for (;;) 40 alloc_free_blocks(); 41 return 0; 42 } 43 main()44int main() { 45 pthread_t th; 46 pthread_create(&th, 0, background, 0); 47 pthread_detach(th); 48 for (int i = 0; i < 10; i++) { 49 int pid = myfork(); 50 if (pid < 0) { 51 fprintf(stderr, "failed to fork (%d)\n", errno); 52 exit(1); 53 } 54 if (pid == 0) { 55 // child 56 exit(0); 57 } 58 // parent 59 while (wait(0) < 0) { 60 } 61 } 62 fprintf(stderr, "DONE\n"); 63 } 64 65 // CHECK: __tsan_test_only_on_fork 66 // CHECK: DONE 67