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