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