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
69extern "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
80int main() { bad_unwind_info(); }
81

source code of libunwind/test/bad_unwind_info.pass.cpp