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