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 
13 long glob = 0;
14 
worker(void * main)15 void *worker(void *main) {
16   glob++;
17   // synchronize with main
18   barrier_wait(&barrier);
19   // synchronize with atfork
20   barrier_wait(&barrier);
21   pthread_kill((pthread_t)main, SIGPROF);
22   barrier_wait(&barrier);
23   // synchronize with afterfork
24   barrier_wait(&barrier);
25   pthread_kill((pthread_t)main, SIGPROF);
26   barrier_wait(&barrier);
27   return NULL;
28 }
29 
atfork()30 void atfork() {
31   barrier_wait(&barrier);
32   barrier_wait(&barrier);
33   write(2, "in atfork\n", strlen("in atfork\n"));
34   static volatile long a;
35   __atomic_fetch_add(&a, 1, __ATOMIC_RELEASE);
36 }
37 
afterfork()38 void afterfork() {
39   barrier_wait(&barrier);
40   barrier_wait(&barrier);
41   write(2, "in afterfork\n", strlen("in afterfork\n"));
42   static volatile long a;
43   __atomic_fetch_add(&a, 1, __ATOMIC_RELEASE);
44 }
45 
afterfork_child()46 void afterfork_child() {
47   write(2, "in afterfork_child\n", strlen("in afterfork_child\n"));
48   glob++;
49 }
50 
handler(int sig)51 void handler(int sig) {
52   write(2, "in handler\n", strlen("in handler\n"));
53   glob++;
54 }
55 
main()56 int main() {
57   barrier_init(&barrier, 2);
58   struct sigaction act = {};
59   act.sa_handler = &handler;
60   if (sigaction(SIGPROF, &act, 0)) {
61     perror("sigaction");
62     exit(1);
63   }
64   pthread_atfork(atfork, afterfork, afterfork_child);
65   pthread_t t;
66   pthread_create(&t, NULL, worker, (void *)pthread_self());
67   barrier_wait(&barrier);
68   pid_t pid = fork();
69   if (pid < 0) {
70     fprintf(stderr, "fork failed: %d\n", errno);
71     return 1;
72   }
73   if (pid == 0) {
74     fprintf(stderr, "CHILD\n");
75     return 0;
76   }
77   if (pid != waitpid(pid, NULL, 0)) {
78     fprintf(stderr, "waitpid failed: %d\n", errno);
79     return 1;
80   }
81   pthread_join(t, NULL);
82   fprintf(stderr, "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