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.
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(size: 10);
27 *(volatile char *)p = 0;
28 blocks[i] = p;
29 }
30 for (int i = 0; i < kBlocks; i++)
31 free(ptr: blocks[i]);
32}
33
34__attribute__((disable_sanitizer_instrumentation)) extern "C" void
35__tsan_test_only_on_fork() {
36 const char *msg = "__tsan_test_only_on_fork\n";
37 write(fd: 2, buf: msg, n: strlen(s: msg));
38 alloc_free_blocks();
39}
40
41static void *background(void *p) {
42 for (;;)
43 alloc_free_blocks();
44 return 0;
45}
46
47int main() {
48 pthread_t th;
49 pthread_create(newthread: &th, attr: 0, start_routine: background, arg: 0);
50 pthread_detach(th: th);
51 for (int i = 0; i < 10; i++) {
52 int pid = myfork();
53 if (pid < 0) {
54 fprintf(stderr, format: "failed to fork (%d)\n", errno);
55 exit(status: 1);
56 }
57 if (pid == 0) {
58 // child
59 exit(status: 0);
60 }
61 // parent
62 while (wait(stat_loc: 0) < 0) {
63 }
64 }
65 fprintf(stderr, format: "DONE\n");
66}
67
68// CHECK: __tsan_test_only_on_fork
69// CHECK: DONE
70

source code of compiler-rt/test/tsan/Darwin/fork_deadlock.cpp