Skip to content

Commit c1eaa11

Browse files
committed
tsan: mark sigwait as blocking
Add a test case reported in: google/sanitizers#1401 and fix it. The code assumes sigwait will process other signals. Reviewed By: vitalybuka Differential Revision: https://reviews.llvm.org/D102057
1 parent 1230b4c commit c1eaa11

File tree

2 files changed

+94
-3
lines changed

2 files changed

+94
-3
lines changed

compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4032,7 +4032,7 @@ INTERCEPTOR(int, sigwait, __sanitizer_sigset_t *set, int *sig) {
40324032
// FIXME: under ASan the call below may write to freed memory and corrupt
40334033
// its metadata. See
40344034
// https://github.com/google/sanitizers/issues/321.
4035-
int res = REAL(sigwait)(set, sig);
4035+
int res = COMMON_INTERCEPTOR_BLOCK_REAL(sigwait)(set, sig);
40364036
if (!res && sig) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sig, sizeof(*sig));
40374037
return res;
40384038
}
@@ -4049,7 +4049,7 @@ INTERCEPTOR(int, sigwaitinfo, __sanitizer_sigset_t *set, void *info) {
40494049
// FIXME: under ASan the call below may write to freed memory and corrupt
40504050
// its metadata. See
40514051
// https://github.com/google/sanitizers/issues/321.
4052-
int res = REAL(sigwaitinfo)(set, info);
4052+
int res = COMMON_INTERCEPTOR_BLOCK_REAL(sigwaitinfo)(set, info);
40534053
if (res > 0 && info) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, info, siginfo_t_sz);
40544054
return res;
40554055
}
@@ -4068,7 +4068,7 @@ INTERCEPTOR(int, sigtimedwait, __sanitizer_sigset_t *set, void *info,
40684068
// FIXME: under ASan the call below may write to freed memory and corrupt
40694069
// its metadata. See
40704070
// https://github.com/google/sanitizers/issues/321.
4071-
int res = REAL(sigtimedwait)(set, info, timeout);
4071+
int res = COMMON_INTERCEPTOR_BLOCK_REAL(sigtimedwait)(set, info, timeout);
40724072
if (res > 0 && info) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, info, siginfo_t_sz);
40734073
return res;
40744074
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
2+
// The test was reported to hang sometimes on Darwin:
3+
// https://lists.llvm.org/pipermail/llvm-commits/Week-of-Mon-20210517/917003.html
4+
// UNSUPPORTED: darwin
5+
6+
#include "test.h"
7+
#include <signal.h>
8+
#include <string.h>
9+
#include <sys/time.h>
10+
11+
int test;
12+
int done;
13+
int signals_handled;
14+
pthread_t main_thread;
15+
pthread_mutex_t mutex;
16+
pthread_cond_t cond;
17+
18+
void timer_handler(int signum) {
19+
write(2, "timer_handler\n", strlen("timer_handler\n"));
20+
if (++signals_handled < 10)
21+
return;
22+
switch (test) {
23+
case 0:
24+
__atomic_store_n(&done, 1, __ATOMIC_RELEASE);
25+
(void)pthread_kill(main_thread, SIGUSR1);
26+
case 1:
27+
if (pthread_mutex_trylock(&mutex) == 0) {
28+
__atomic_store_n(&done, 1, __ATOMIC_RELEASE);
29+
pthread_cond_signal(&cond);
30+
pthread_mutex_unlock(&mutex);
31+
}
32+
case 2:
33+
__atomic_store_n(&done, 1, __ATOMIC_RELEASE);
34+
}
35+
}
36+
37+
int main(int argc, char **argv) {
38+
main_thread = pthread_self();
39+
pthread_mutex_init(&mutex, 0);
40+
pthread_cond_init(&cond, 0);
41+
42+
sigset_t sigset;
43+
sigemptyset(&sigset);
44+
sigaddset(&sigset, SIGUSR1);
45+
if (sigprocmask(SIG_BLOCK, &sigset, NULL))
46+
exit((perror("sigprocmask"), 1));
47+
48+
struct sigaction sa;
49+
memset(&sa, 0, sizeof(sa));
50+
sa.sa_handler = &timer_handler;
51+
if (sigaction(SIGALRM, &sa, NULL))
52+
exit((perror("setitimer"), 1));
53+
54+
for (test = 0; test < 3; test++) {
55+
fprintf(stderr, "test %d\n", test);
56+
struct itimerval timer;
57+
timer.it_value.tv_sec = 0;
58+
timer.it_value.tv_usec = 50000;
59+
timer.it_interval = timer.it_value;
60+
if (setitimer(ITIMER_REAL, &timer, NULL))
61+
exit((perror("setitimer"), 1));
62+
63+
switch (test) {
64+
case 0:
65+
while (__atomic_load_n(&done, __ATOMIC_ACQUIRE) == 0) {
66+
int signum;
67+
sigwait(&sigset, &signum);
68+
write(2, "sigwait\n", strlen("sigwait\n"));
69+
}
70+
case 1:
71+
pthread_mutex_lock(&mutex);
72+
while (__atomic_load_n(&done, __ATOMIC_ACQUIRE) == 0) {
73+
pthread_cond_wait(&cond, &mutex);
74+
write(2, "pthread_cond_wait\n", strlen("pthread_cond_wait\n"));
75+
}
76+
pthread_mutex_unlock(&mutex);
77+
case 2:
78+
while (__atomic_load_n(&done, __ATOMIC_ACQUIRE) == 0) {
79+
}
80+
}
81+
82+
memset(&timer, 0, sizeof(timer));
83+
if (setitimer(ITIMER_REAL, &timer, NULL))
84+
exit((perror("setitimer"), 1));
85+
done = 0;
86+
signals_handled = 0;
87+
}
88+
fprintf(stderr, "DONE\n");
89+
}
90+
91+
// CHECK: DONE

0 commit comments

Comments
 (0)