1// RUN: %clangxx_tsan %s -o %t && %run %t 2>&1 | FileCheck %s
2// UNSUPPORTED: darwin
3
4#include <errno.h>
5#include <limits.h>
6#include <pthread.h>
7#include <signal.h>
8#include <stdio.h>
9#include <stdlib.h>
10#include <sys/select.h>
11#include <sys/time.h>
12#include <sys/types.h>
13#include <unistd.h>
14
15// This attempts to exercise a race condition where both a thread and its signal
16// handler allocate the SigCtx. If the race is allowed, it leads to a leak and
17// the first signal being dropped.
18// Spawn threads in a loop and send it SIGUSR1 concurrently with the thread
19// doing a bogus kill() call. The signal handler writes to a self-pipe which the
20// thread detects and then exits. A dropped signal results in a timeout.
21int pipes[2];
22static void handler(int sig) { write(fd: pipes[1], buf: "x", n: 1); }
23
24static int do_select() {
25 struct timeval tvs {
26 .tv_sec: 0, .tv_usec: 1000
27 };
28 fd_set fds;
29 FD_ZERO(&fds);
30 FD_SET(pipes[0], &fds);
31 return select(nfds: pipes[0] + 1, readfds: &fds, writefds: 0, exceptfds: 0, timeout: &tvs);
32}
33
34static void *thr(void *p) {
35 // This kill() is expected to fail; it exists only to trigger a call to SigCtx
36 // outside of the signal handler.
37 kill(INT_MIN, sig: 0);
38 int success = 0;
39 for (int i = 0; i < 1024; i++) {
40 if (do_select() > 0) {
41 success = 1;
42 break;
43 }
44 }
45 if (success) {
46 char c;
47 read(fd: pipes[0], buf: &c, nbytes: 1);
48 } else {
49 fprintf(stderr, format: "Failed to receive signal\n");
50 exit(status: 1);
51 }
52 return p;
53}
54
55int main() {
56 if (pipe(pipedes: pipes)) {
57 perror(s: "pipe");
58 exit(status: 1);
59 }
60
61 struct sigaction act = {};
62 act.sa_handler = &handler;
63 if (sigaction(SIGUSR1, act: &act, oact: 0)) {
64 perror(s: "sigaction");
65 exit(status: 1);
66 }
67
68 for (int i = 0; i < (1 << 10); i++) {
69 pthread_t th{};
70 if (pthread_create(newthread: &th, attr: 0, start_routine: thr, arg: 0)) {
71 perror(s: "pthread_create");
72 exit(status: 1);
73 }
74 pthread_kill(threadid: th, SIGUSR1);
75 pthread_join(th: th, thread_return: 0);
76 }
77
78 fprintf(stderr, format: "DONE\n");
79 return 0;
80}
81
82// CHECK-NOT: WARNING: ThreadSanitizer:
83// CHECK: DONE
84// CHECK-NOT: WARNING: ThreadSanitizer:
85

source code of compiler-rt/test/tsan/signal_thread_sigctx_race.cpp