1// RUN: %clangxx_tsan -O0 %s -o %t && %run %t 2>&1 | FileCheck %s
2// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
3
4#include "test.h"
5#include <setjmp.h>
6
7__attribute__((noinline)) void throws_int() {
8 throw 42;
9}
10
11__attribute__((noinline)) void callee_throws() {
12 try {
13 throws_int();
14 } catch (int) {
15 fprintf(stderr, "callee_throws caught exception\n");
16 }
17}
18
19__attribute__((noinline)) void throws_catches_rethrows() {
20 try {
21 throws_int();
22 } catch (int) {
23 fprintf(stderr, "throws_catches_rethrows caught exception\n");
24 throw;
25 }
26}
27
28__attribute__((noinline)) void callee_rethrows() {
29 try {
30 throws_catches_rethrows();
31 } catch (int) {
32 fprintf(stderr, "callee_rethrows caught exception\n");
33 }
34}
35
36__attribute__((noinline)) void throws_and_catches() {
37 try {
38 throws_int();
39 } catch (int) {
40 fprintf(stderr, "throws_and_catches caught exception\n");
41 }
42}
43
44__attribute__((noinline)) void nested_try() {
45 try {
46 try {
47 throws_int();
48 } catch (double) {
49 fprintf(stderr, "nested_try inner block caught exception\n");
50 }
51 } catch (int) {
52 fprintf(stderr, "nested_try outer block caught exception\n");
53 }
54}
55
56__attribute__((noinline)) void nested_try2() {
57 try {
58 try {
59 throws_int();
60 } catch (int) {
61 fprintf(stderr, "nested_try inner block caught exception\n");
62 }
63 } catch (double) {
64 fprintf(stderr, "nested_try outer block caught exception\n");
65 }
66}
67
68class ClassWithDestructor {
69 public:
70 ClassWithDestructor() {
71 fprintf(stderr, "ClassWithDestructor\n");
72 }
73 ~ClassWithDestructor() {
74 fprintf(stderr, "~ClassWithDestructor\n");
75 }
76};
77
78__attribute__((noinline)) void local_object_then_throw() {
79 ClassWithDestructor obj;
80 throws_int();
81}
82
83__attribute__((noinline)) void cpp_object_with_destructor() {
84 try {
85 local_object_then_throw();
86 } catch (int) {
87 fprintf(stderr, "cpp_object_with_destructor caught exception\n");
88 }
89}
90
91__attribute__((noinline)) void recursive_call(long n) {
92 if (n > 0) {
93 recursive_call(n - 1);
94 } else {
95 throws_int();
96 }
97}
98
99__attribute__((noinline)) void multiframe_unwind() {
100 try {
101 recursive_call(5);
102 } catch (int) {
103 fprintf(stderr, "multiframe_unwind caught exception\n");
104 }
105}
106
107__attribute__((noinline)) void longjmp_unwind() {
108 jmp_buf env;
109 int i = setjmp(env);
110 if (i != 0) {
111 fprintf(stderr, "longjmp_unwind jumped\n");
112 return;
113 }
114
115 try {
116 longjmp(env, 42);
117 } catch (int) {
118 fprintf(stderr, "longjmp_unwind caught exception\n");
119 }
120}
121
122__attribute__((noinline)) void recursive_call_longjmp(jmp_buf env, long n) {
123 if (n > 0) {
124 recursive_call_longjmp(env, n - 1);
125 } else {
126 longjmp(env, 42);
127 }
128}
129
130__attribute__((noinline)) void longjmp_unwind_multiple_frames() {
131 jmp_buf env;
132 int i = setjmp(env);
133 if (i != 0) {
134 fprintf(stderr, "longjmp_unwind_multiple_frames jumped\n");
135 return;
136 }
137
138 try {
139 recursive_call_longjmp(env, 5);
140 } catch (int) {
141 fprintf(stderr, "longjmp_unwind_multiple_frames caught exception\n");
142 }
143}
144
145#define CHECK_SHADOW_STACK(val) \
146 fprintf(stderr, (val == __tsan_testonly_shadow_stack_current_size() \
147 ? "OK.\n" \
148 : "Shadow stack leak!\n"));
149
150int main(int argc, const char * argv[]) {
151 fprintf(stderr, "Hello, World!\n");
152 unsigned long shadow_stack_size = __tsan_testonly_shadow_stack_current_size();
153
154 throws_and_catches();
155 CHECK_SHADOW_STACK(shadow_stack_size);
156
157 callee_throws();
158 CHECK_SHADOW_STACK(shadow_stack_size);
159
160 callee_rethrows();
161 CHECK_SHADOW_STACK(shadow_stack_size);
162
163 nested_try();
164 CHECK_SHADOW_STACK(shadow_stack_size);
165
166 nested_try2();
167 CHECK_SHADOW_STACK(shadow_stack_size);
168
169 cpp_object_with_destructor();
170 CHECK_SHADOW_STACK(shadow_stack_size);
171
172 multiframe_unwind();
173 CHECK_SHADOW_STACK(shadow_stack_size);
174
175 longjmp_unwind();
176 CHECK_SHADOW_STACK(shadow_stack_size);
177
178 longjmp_unwind_multiple_frames();
179 CHECK_SHADOW_STACK(shadow_stack_size);
180
181 return 0;
182}
183
184// CHECK: Hello, World!
185// CHECK-NOT: Shadow stack leak
186