1 | // This test is broken with shared libstdc++ / libc++ on Android. |
2 | // RUN: %clangxx_hwasan -static-libstdc++ %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=GOOD |
3 | // RUN: %clangxx_hwasan -static-libstdc++ -DMALLOCEDSTACK %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=GOOD |
4 | // RUN: %clangxx_hwasan -static-libstdc++ -DNO_SANITIZE_F %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=GOOD |
5 | // RUN: %clangxx_hwasan_oldrt -static-libstdc++ %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=GOOD |
6 | // RUN: %clangxx_hwasan_oldrt -static-libstdc++ %s -mllvm -hwasan-instrument-landing-pads=0 -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=BAD |
7 | |
8 | // C++ tests on x86_64 require instrumented libc++/libstdc++. |
9 | // RISC-V target doesn't support oldrt |
10 | // REQUIRES: aarch64-target-arch |
11 | |
12 | #include <cassert> |
13 | #include <cstdio> |
14 | #include <errno.h> |
15 | #include <limits.h> |
16 | #include <pthread.h> |
17 | #include <sanitizer/hwasan_interface.h> |
18 | #include <stdexcept> |
19 | #include <string.h> |
20 | |
21 | static void optimization_barrier(void* arg) { |
22 | asm volatile("" : : "r" (arg) : "memory" ); |
23 | } |
24 | |
25 | __attribute__((noinline)) |
26 | void h() { |
27 | char x[1000]; |
28 | optimization_barrier(arg: x); |
29 | throw std::runtime_error("hello" ); |
30 | } |
31 | |
32 | __attribute__((noinline)) |
33 | void g() { |
34 | char x[1000]; |
35 | optimization_barrier(arg: x); |
36 | h(); |
37 | optimization_barrier(arg: x); |
38 | } |
39 | |
40 | __attribute__((noinline)) |
41 | void hwasan_read(char *p, int size) { |
42 | char volatile sink; |
43 | for (int i = 0; i < size; ++i) |
44 | sink = p[i]; |
45 | } |
46 | |
47 | __attribute__((noinline, no_sanitize("hwaddress" ))) void after_catch() { |
48 | char x[10000]; |
49 | hwasan_read(p: &x[0], size: sizeof(x)); |
50 | } |
51 | |
52 | __attribute__((noinline)) |
53 | #ifdef NO_SANITIZE_F |
54 | __attribute__((no_sanitize("hwaddress" ))) |
55 | #endif |
56 | void * |
57 | f(void *) { |
58 | char x[1000]; |
59 | try { |
60 | // Put two tagged frames on the stack, throw an exception from the deepest one. |
61 | g(); |
62 | } catch (const std::runtime_error &e) { |
63 | // Put an untagged frame on stack, check that it is indeed untagged. |
64 | // This relies on exception support zeroing out stack tags. |
65 | // BAD: tag-mismatch |
66 | after_catch(); |
67 | // Check that an in-scope stack allocation is still tagged. |
68 | // This relies on exception support not zeroing too much. |
69 | hwasan_read(p: &x[0], size: sizeof(x)); |
70 | // GOOD: hello |
71 | printf("%s\n" , e.what()); |
72 | } |
73 | return nullptr; |
74 | } |
75 | |
76 | int main() { |
77 | __hwasan_enable_allocator_tagging(); |
78 | #ifdef MALLOCEDSTACK |
79 | pthread_attr_t attr; |
80 | void *stack = malloc(PTHREAD_STACK_MIN); |
81 | assert(pthread_attr_init(&attr) == 0); |
82 | if (pthread_attr_setstack(&attr, stack, PTHREAD_STACK_MIN) != 0) { |
83 | fprintf(stderr, "pthread_attr_setstack: %s" , strerror(errno)); |
84 | abort(); |
85 | } |
86 | pthread_t thid; |
87 | if (pthread_create(&thid, &attr, f, nullptr) != 0) { |
88 | fprintf(stderr, "pthread_create: %s" , strerror(errno)); |
89 | abort(); |
90 | } |
91 | void *ret; |
92 | if (pthread_join(thid, &ret) != 0) { |
93 | fprintf(stderr, "pthread_join: %s" , strerror(errno)); |
94 | abort(); |
95 | } |
96 | assert(pthread_attr_destroy(&attr) == 0); |
97 | free(stack); |
98 | #else |
99 | f(nullptr); |
100 | #endif |
101 | } |
102 | |