| 1 | // -*- C++ -*- |
| 2 | //===----------------------------------------------------------------------===// |
| 3 | // |
| 4 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 5 | // See https://llvm.org/LICENSE.txt for license information. |
| 6 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | |
| 10 | // Ensure that libunwind doesn't crash on invalid info; the Linux aarch64 |
| 11 | // sigreturn frame check would previously attempt to access invalid memory in |
| 12 | // this scenario. |
| 13 | // REQUIRES: target={{(aarch64|s390x|x86_64)-.+linux.*}} |
| 14 | |
| 15 | // GCC doesn't support __attribute__((naked)) on AArch64. |
| 16 | // UNSUPPORTED: gcc |
| 17 | |
| 18 | // Inline assembly is incompatible with MSAN. |
| 19 | // UNSUPPORTED: msan |
| 20 | |
| 21 | #undef NDEBUG |
| 22 | #include <assert.h> |
| 23 | #include <libunwind.h> |
| 24 | #include <stdio.h> |
| 25 | |
| 26 | __attribute__((naked)) void bad_unwind_info() { |
| 27 | #if defined(__aarch64__) |
| 28 | __asm__("// not using 0 because unwinder was already resilient to that\n" |
| 29 | "mov x8, #4\n" |
| 30 | "stp x30, x8, [sp, #-16]!\n" |
| 31 | ".cfi_def_cfa_offset 16\n" |
| 32 | "// purposely use incorrect offset for x30\n" |
| 33 | ".cfi_offset x30, -8\n" |
| 34 | "bl stepper\n" |
| 35 | "ldr x30, [sp], #16\n" |
| 36 | ".cfi_def_cfa_offset 0\n" |
| 37 | ".cfi_restore x30\n" |
| 38 | "ret\n" ); |
| 39 | #elif defined(__s390x__) |
| 40 | __asm__("stmg %r14,%r15,112(%r15)\n" |
| 41 | "mvghi 104(%r15),4\n" |
| 42 | "# purposely use incorrect offset for %r14\n" |
| 43 | ".cfi_offset 14, -56\n" |
| 44 | ".cfi_offset 15, -40\n" |
| 45 | "lay %r15,-160(%r15)\n" |
| 46 | ".cfi_def_cfa_offset 320\n" |
| 47 | "brasl %r14,stepper\n" |
| 48 | "lmg %r14,%r15,272(%r15)\n" |
| 49 | ".cfi_restore 15\n" |
| 50 | ".cfi_restore 14\n" |
| 51 | ".cfi_def_cfa_offset 160\n" |
| 52 | "br %r14\n" ); |
| 53 | #elif defined(__x86_64__) |
| 54 | __asm__("pushq %rbx\n" |
| 55 | ".cfi_def_cfa_offset 16\n" |
| 56 | "movq 8(%rsp), %rbx\n" |
| 57 | "# purposely corrupt return value on stack\n" |
| 58 | "movq $4, 8(%rsp)\n" |
| 59 | "callq stepper\n" |
| 60 | "movq %rbx, 8(%rsp)\n" |
| 61 | "popq %rbx\n" |
| 62 | ".cfi_def_cfa_offset 8\n" |
| 63 | "ret\n" ); |
| 64 | #else |
| 65 | #error This test is only supported on aarch64, s390x, or x86-64 |
| 66 | #endif |
| 67 | } |
| 68 | |
| 69 | extern "C" void stepper() { |
| 70 | unw_cursor_t cursor; |
| 71 | unw_context_t uc; |
| 72 | unw_getcontext(&uc); |
| 73 | unw_init_local(&cursor, &uc); |
| 74 | // stepping to bad_unwind_info should succeed |
| 75 | assert(unw_step(&cursor) > 0); |
| 76 | // stepping past bad_unwind_info should fail but not crash |
| 77 | assert(unw_step(&cursor) <= 0); |
| 78 | } |
| 79 | |
| 80 | int main() { bad_unwind_info(); } |
| 81 | |