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)41static void *background(void *p) { 42 for (;;) 43 alloc_free_blocks(); 44 return 0; 45 } 46 main()47int 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