16a395824SDmitry Vyukov // RUN: %clangxx_tsan -O1 %s -o %t && %env_tsan_opts=atexit_sleep_ms=0 %run %t 2>&1 | FileCheck %s 26a395824SDmitry Vyukov 36a395824SDmitry Vyukov // This test models what happens on Mac when fork 46a395824SDmitry Vyukov // calls malloc/free inside of our atfork callbacks. 56a395824SDmitry Vyukov // and ensures that we don't deadlock on malloc/free calls. 66a395824SDmitry Vyukov 76a395824SDmitry Vyukov #include "../test.h" 86a395824SDmitry Vyukov #include "syscall.h" 96a395824SDmitry Vyukov #include <errno.h> 106a395824SDmitry Vyukov #include <string.h> 116a395824SDmitry Vyukov #include <sys/types.h> 126a395824SDmitry Vyukov #include <sys/wait.h> 136a395824SDmitry Vyukov 14*be77afe4SAlexander Potapenko // disable_sanitizer_instrumentation on __tsan_test_only_on_fork is not 15*be77afe4SAlexander Potapenko // transitive, so we must apply it here as well. 16*be77afe4SAlexander Potapenko // Instrumenting alloc_free_blocks() will result in deadlocks in TSan. alloc_free_blocks()17*be77afe4SAlexander Potapenko__attribute__((disable_sanitizer_instrumentation)) void alloc_free_blocks() { 186a395824SDmitry Vyukov // Allocate a bunch of blocks to drain local allocator cache 196a395824SDmitry Vyukov // and provoke it to lock allocator global mutexes. 206a395824SDmitry Vyukov const int kBlocks = 1000; 216a395824SDmitry Vyukov void *blocks[kBlocks]; 226a395824SDmitry Vyukov for (int i = 0; i < kBlocks; i++) { 236a395824SDmitry Vyukov void *p = malloc(10); 246a395824SDmitry Vyukov *(volatile char *)p = 0; 256a395824SDmitry Vyukov blocks[i] = p; 266a395824SDmitry Vyukov } 276a395824SDmitry Vyukov for (int i = 0; i < kBlocks; i++) 286a395824SDmitry Vyukov free(blocks[i]); 296a395824SDmitry Vyukov } 306a395824SDmitry Vyukov 316a395824SDmitry Vyukov __attribute__((disable_sanitizer_instrumentation)) extern "C" void __tsan_test_only_on_fork()326a395824SDmitry Vyukov__tsan_test_only_on_fork() { 336a395824SDmitry Vyukov const char *msg = "__tsan_test_only_on_fork\n"; 346a395824SDmitry Vyukov write(2, msg, strlen(msg)); 356a395824SDmitry Vyukov alloc_free_blocks(); 366a395824SDmitry Vyukov } 376a395824SDmitry Vyukov background(void * p)386a395824SDmitry Vyukovstatic void *background(void *p) { 396a395824SDmitry Vyukov for (;;) 406a395824SDmitry Vyukov alloc_free_blocks(); 416a395824SDmitry Vyukov return 0; 426a395824SDmitry Vyukov } 436a395824SDmitry Vyukov main()446a395824SDmitry Vyukovint main() { 456a395824SDmitry Vyukov pthread_t th; 466a395824SDmitry Vyukov pthread_create(&th, 0, background, 0); 476a395824SDmitry Vyukov pthread_detach(th); 486a395824SDmitry Vyukov for (int i = 0; i < 10; i++) { 496a395824SDmitry Vyukov int pid = myfork(); 506a395824SDmitry Vyukov if (pid < 0) { 516a395824SDmitry Vyukov fprintf(stderr, "failed to fork (%d)\n", errno); 526a395824SDmitry Vyukov exit(1); 536a395824SDmitry Vyukov } 546a395824SDmitry Vyukov if (pid == 0) { 556a395824SDmitry Vyukov // child 566a395824SDmitry Vyukov exit(0); 576a395824SDmitry Vyukov } 586a395824SDmitry Vyukov // parent 596a395824SDmitry Vyukov while (wait(0) < 0) { 606a395824SDmitry Vyukov } 616a395824SDmitry Vyukov } 626a395824SDmitry Vyukov fprintf(stderr, "DONE\n"); 636a395824SDmitry Vyukov } 646a395824SDmitry Vyukov 656a395824SDmitry Vyukov // CHECK: __tsan_test_only_on_fork 666a395824SDmitry Vyukov // CHECK: DONE 67