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