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 68 class 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 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