1 // RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
2 
3 // Test case for longjumping out of signal handler:
4 // https://github.com/google/sanitizers/issues/482
5 
6 // Longjmp assembly has not been implemented for mips64 yet
7 // XFAIL: mips64
8 // This test fails on powerpc64 BE (VMA=44), a segmentation fault
9 // error happens at the second assignment
10 // "((volatile int *volatile)mem)[1] = 1".
11 // XFAIL: powerpc64-unknown-linux-gnu
12 
13 #include <setjmp.h>
14 #include <signal.h>
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <sys/mman.h>
18 
19 #ifdef __APPLE__
20 #define SIGNAL_TO_HANDLE SIGBUS
21 #else
22 #define SIGNAL_TO_HANDLE SIGSEGV
23 #endif
24 
25 sigjmp_buf fault_jmp;
26 volatile int fault_expected;
27 
sigfault_handler(int sig)28 void sigfault_handler(int sig) {
29   if (!fault_expected)
30     abort();
31 
32   /* just return from sighandler to proper place */
33   fault_expected = 0;
34   siglongjmp(fault_jmp, 1);
35 }
36 
37 #define MUST_FAULT(code) do { \
38   fault_expected = 1; \
39   if (!sigsetjmp(fault_jmp, 1)) { \
40     code; /* should pagefault -> sihandler does longjmp */ \
41     fprintf(stderr, "%s not faulted\n", #code); \
42     abort(); \
43   } else { \
44     fprintf(stderr, "%s faulted ok\n", #code); \
45   } \
46 } while (0)
47 
main()48 int main() {
49   struct sigaction act;
50   act.sa_handler  = sigfault_handler;
51   act.sa_flags    = 0;
52   if (sigemptyset(&act.sa_mask)) {
53     perror("sigemptyset");
54     exit(1);
55   }
56 
57   if (sigaction(SIGNAL_TO_HANDLE, &act, NULL)) {
58     perror("sigaction");
59     exit(1);
60   }
61 
62   void *mem = mmap(0, 4096, PROT_NONE, MAP_PRIVATE | MAP_ANON,
63       -1, 0);
64 
65   MUST_FAULT(((volatile int *volatile)mem)[0] = 0);
66   MUST_FAULT(((volatile int *volatile)mem)[1] = 1);
67   MUST_FAULT(((volatile int *volatile)mem)[3] = 1);
68 
69   // Ensure that tsan does not think that we are
70   // in a signal handler.
71   void *volatile p = malloc(10);
72   ((volatile int*)p)[1] = 1;
73   free((void*)p);
74 
75   munmap(p, 4096);
76 
77   fprintf(stderr, "DONE\n");
78   return 0;
79 }
80 
81 // CHECK-NOT: WARNING: ThreadSanitizer
82 // CHECK: DONE
83