forked from OSchip/llvm-project
67 lines
2.1 KiB
C++
67 lines
2.1 KiB
C++
// -*- C++ -*-
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Ensure that libunwind doesn't crash on invalid info; the Linux aarch64
|
|
// sigreturn frame check would previously attempt to access invalid memory in
|
|
// this scenario.
|
|
// REQUIRES: linux && (target={{aarch64-.+}} || target={{x86_64-.+}})
|
|
|
|
// GCC doesn't support __attribute__((naked)) on AArch64.
|
|
// UNSUPPORTED: gcc
|
|
|
|
// Inline assembly is incompatible with MSAN.
|
|
// UNSUPPORTED: msan
|
|
|
|
#undef NDEBUG
|
|
#include <assert.h>
|
|
#include <libunwind.h>
|
|
#include <stdio.h>
|
|
|
|
__attribute__((naked)) void bad_unwind_info() {
|
|
#if defined(__aarch64__)
|
|
__asm__("// not using 0 because unwinder was already resilient to that\n"
|
|
"mov x8, #4\n"
|
|
"stp x30, x8, [sp, #-16]!\n"
|
|
".cfi_def_cfa_offset 16\n"
|
|
"// purposely use incorrect offset for x30\n"
|
|
".cfi_offset x30, -8\n"
|
|
"bl stepper\n"
|
|
"ldr x30, [sp], #16\n"
|
|
".cfi_def_cfa_offset 0\n"
|
|
".cfi_restore x30\n"
|
|
"ret\n");
|
|
#elif defined(__x86_64__)
|
|
__asm__("pushq %rbx\n"
|
|
".cfi_def_cfa_offset 16\n"
|
|
"movq 8(%rsp), %rbx\n"
|
|
"# purposely corrupt return value on stack\n"
|
|
"movq $4, 8(%rsp)\n"
|
|
"callq stepper\n"
|
|
"movq %rbx, 8(%rsp)\n"
|
|
"popq %rbx\n"
|
|
".cfi_def_cfa_offset 8\n"
|
|
"ret\n");
|
|
#else
|
|
#error This test is only supported on aarch64 or x86-64
|
|
#endif
|
|
}
|
|
|
|
extern "C" void stepper() {
|
|
unw_cursor_t cursor;
|
|
unw_context_t uc;
|
|
unw_getcontext(&uc);
|
|
unw_init_local(&cursor, &uc);
|
|
// stepping to bad_unwind_info should succeed
|
|
assert(unw_step(&cursor) > 0);
|
|
// stepping past bad_unwind_info should fail but not crash
|
|
assert(unw_step(&cursor) <= 0);
|
|
}
|
|
|
|
int main() { bad_unwind_info(); }
|