1 // Regression test for
2 // https://code.google.com/p/address-sanitizer/issues/detail?id=180
3 
4 // RUN: %clangxx -O0 %s -o %t
5 
6 // RUN: %env_tool_opts=handle_segv=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK0
7 // RUN: %env_tool_opts=handle_segv=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1
8 // RUN: %env_tool_opts=handle_segv=2 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2
9 
10 // RUN: %env_tool_opts=handle_segv=0:allow_user_segv_handler=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK0
11 // RUN: %env_tool_opts=handle_segv=1:allow_user_segv_handler=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2
12 // RUN: %env_tool_opts=handle_segv=2:allow_user_segv_handler=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2
13 
14 // RUN: %env_tool_opts=handle_segv=0:allow_user_segv_handler=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK0
15 // RUN: %env_tool_opts=handle_segv=1:allow_user_segv_handler=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1
16 // RUN: %env_tool_opts=handle_segv=2:allow_user_segv_handler=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2
17 
18 // Flaky errors in debuggerd with "waitpid returned unexpected pid (0)" in logcat.
19 // UNSUPPORTED: android && i386-target-arch
20 
21 #include <signal.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 
25 struct sigaction original_sigaction_sigbus;
26 struct sigaction original_sigaction_sigsegv;
27 
28 void User_OnSIGSEGV(int signum, siginfo_t *siginfo, void *context) {
29   fprintf(stderr, "User sigaction called\n");
30   struct sigaction original_sigaction = {};
31   if (signum == SIGBUS)
32     original_sigaction = original_sigaction_sigbus;
33   else if (signum == SIGSEGV)
34     original_sigaction = original_sigaction_sigsegv;
35   else {
36     printf("Invalid signum");
37     exit(1);
38   }
39   if (original_sigaction.sa_flags | SA_SIGINFO) {
40     if (original_sigaction.sa_sigaction)
41       original_sigaction.sa_sigaction(signum, siginfo, context);
42   } else {
43     if (original_sigaction.sa_handler)
44       original_sigaction.sa_handler(signum);
45   }
46   exit(1);
47 }
48 
49 int DoSEGV() {
50   volatile int *x = 0;
51   return *x;
52 }
53 
54 bool InstallHandler(int signum, struct sigaction *original_sigaction) {
55   struct sigaction user_sigaction = {};
56   user_sigaction.sa_sigaction = User_OnSIGSEGV;
57   user_sigaction.sa_flags = SA_SIGINFO;
58   if (sigaction(signum, &user_sigaction, original_sigaction)) {
59     perror("sigaction");
60     return false;
61   }
62   return true;
63 }
64 
65 int main() {
66   // Let's install handlers for both SIGSEGV and SIGBUS, since pre-Yosemite
67   // 32-bit Darwin triggers SIGBUS instead.
68   if (InstallHandler(SIGSEGV, &original_sigaction_sigsegv) &&
69       InstallHandler(SIGBUS, &original_sigaction_sigbus)) {
70     fprintf(stderr, "User sigaction installed\n");
71   }
72   return DoSEGV();
73 }
74 
75 // CHECK0-NOT: Sanitizer:DEADLYSIGNAL
76 // CHECK0-NOT: Sanitizer: SEGV on unknown address
77 // CHECK0: User sigaction installed
78 // CHECK0-NEXT: User sigaction called
79 
80 // CHECK1: User sigaction installed
81 // CHECK1-NEXT: User sigaction called
82 // CHECK1-NEXT: Sanitizer:DEADLYSIGNAL
83 // CHECK1: Sanitizer: SEGV on unknown address
84 
85 // CHECK2-NOT: User sigaction called
86 // CHECK2: User sigaction installed
87 // CHECK2-NEXT: Sanitizer:DEADLYSIGNAL
88 // CHECK2: Sanitizer: SEGV on unknown address
89