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
throws_int()7 __attribute__((noinline)) void throws_int() {
8 throw 42;
9 }
10
callee_throws()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
throws_catches_rethrows()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
callee_rethrows()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
throws_and_catches()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
nested_try()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
nested_try2()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
68 class ClassWithDestructor {
69 public:
ClassWithDestructor()70 ClassWithDestructor() {
71 fprintf(stderr, "ClassWithDestructor\n");
72 }
~ClassWithDestructor()73 ~ClassWithDestructor() {
74 fprintf(stderr, "~ClassWithDestructor\n");
75 }
76 };
77
local_object_then_throw()78 __attribute__((noinline)) void local_object_then_throw() {
79 ClassWithDestructor obj;
80 throws_int();
81 }
82
cpp_object_with_destructor()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
recursive_call(long n)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
multiframe_unwind()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
longjmp_unwind()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
recursive_call_longjmp(jmp_buf env,long n)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
longjmp_unwind_multiple_frames()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
main(int argc,const char * argv[])150 int 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