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