1// RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t > %t.out
2// RUN: FileCheck %s --check-prefixes=CHECK,PARENT --input-file %t.out
3// RUN: FileCheck %s --check-prefixes=CHECK,CHILD --input-file %t.out
4// Regression test for
5// https://groups.google.com/g/thread-sanitizer/c/TQrr4-9PRYo/m/HFR4FMi6AQAJ
6#include "test.h"
7#include <errno.h>
8#include <signal.h>
9#include <string.h>
10#include <sys/types.h>
11#include <sys/wait.h>
12
13long glob = 0;
14
15void *worker(void *main) {
16 glob++;
17 // synchronize with main
18 barrier_wait(barrier: &barrier);
19 // synchronize with atfork
20 barrier_wait(barrier: &barrier);
21 pthread_kill(threadid: (pthread_t)main, SIGPROF);
22 barrier_wait(barrier: &barrier);
23 // synchronize with afterfork
24 barrier_wait(barrier: &barrier);
25 pthread_kill(threadid: (pthread_t)main, SIGPROF);
26 barrier_wait(barrier: &barrier);
27 return NULL;
28}
29
30void atfork() {
31 barrier_wait(barrier: &barrier);
32 barrier_wait(barrier: &barrier);
33 write(fd: 2, buf: "in atfork\n", n: strlen(s: "in atfork\n"));
34 static volatile long a;
35 __atomic_fetch_add(&a, 1, __ATOMIC_RELEASE);
36}
37
38void afterfork() {
39 barrier_wait(barrier: &barrier);
40 barrier_wait(barrier: &barrier);
41 write(fd: 2, buf: "in afterfork\n", n: strlen(s: "in afterfork\n"));
42 static volatile long a;
43 __atomic_fetch_add(&a, 1, __ATOMIC_RELEASE);
44}
45
46void afterfork_child() {
47 write(fd: 2, buf: "in afterfork_child\n", n: strlen(s: "in afterfork_child\n"));
48 glob++;
49}
50
51void handler(int sig) {
52 write(fd: 2, buf: "in handler\n", n: strlen(s: "in handler\n"));
53 glob++;
54}
55
56int main() {
57 barrier_init(barrier: &barrier, count: 2);
58 struct sigaction act = {};
59 act.sa_handler = &handler;
60 if (sigaction(SIGPROF, act: &act, oact: 0)) {
61 perror(s: "sigaction");
62 exit(status: 1);
63 }
64 pthread_atfork(prepare: atfork, parent: afterfork, child: afterfork_child);
65 pthread_t t;
66 pthread_create(newthread: &t, NULL, start_routine: worker, arg: (void *)pthread_self());
67 barrier_wait(barrier: &barrier);
68 pid_t pid = fork();
69 if (pid < 0) {
70 fprintf(stderr, format: "fork failed: %d\n", errno);
71 return 1;
72 }
73 if (pid == 0) {
74 fprintf(stderr, format: "CHILD\n");
75 return 0;
76 }
77 if (pid != waitpid(pid: pid, NULL, options: 0)) {
78 fprintf(stderr, format: "waitpid failed: %d\n", errno);
79 return 1;
80 }
81 pthread_join(th: t, NULL);
82 fprintf(stderr, format: "PARENT\n");
83 return 0;
84}
85
86// CHECK: in atfork
87// CHECK: in handler
88// CHECK: ThreadSanitizer: data race
89// CHECK: Write of size 8
90// CHECK: #0 handler
91// CHECK: Previous write of size 8
92// CHECK: #0 worker
93// PARENT: afterfork
94// PARENT: in handler
95// CHILD: afterfork_child
96// CHILD: CHILD
97// CHECK: PARENT
98

source code of compiler-rt/test/tsan/pthread_atfork_deadlock3.c