deduplicate abort implementations

Currently, the code for process aborts is duplicated across `panic_abort` and `std`. This PR uses `#[rustc_std_internal_symbol]` to make the `std` implementation available to `panic_abort` via the linker, thereby deduplicating the code.
This commit is contained in:
joboet 2025-03-29 12:16:49 +01:00
parent 414482f6a0
commit b7f2cd3a2b
No known key found for this signature in database
GPG key ID: 704E0149B0194B3C
11 changed files with 43 additions and 117 deletions

View file

@ -196,7 +196,6 @@ name = "panic_abort"
version = "0.0.0"
dependencies = [
"alloc",
"cfg-if",
"compiler_builtins",
"core",
"libc",

View file

@ -12,10 +12,11 @@ bench = false
doc = false
[dependencies]
alloc = { path = "../alloc" }
cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] }
core = { path = "../core" }
compiler_builtins = "0.1.0"
[target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies]
[target.'cfg(target_os = "android")'.dependencies]
libc = { version = "0.2", default-features = false }
[target.'cfg(any(target_os = "android", target_os = "zkvm"))'.dependencies]
alloc = { path = "../alloc" }

View file

@ -7,15 +7,11 @@
#![unstable(feature = "panic_abort", issue = "32837")]
#![doc(issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")]
#![panic_runtime]
#![allow(unused_features)]
#![feature(asm_experimental_arch)]
#![feature(core_intrinsics)]
#![feature(panic_runtime)]
#![feature(std_internals)]
#![feature(staged_api)]
#![feature(rustc_attrs)]
#![allow(internal_features)]
#![deny(unsafe_op_in_unsafe_fn)]
#[cfg(target_os = "android")]
mod android;
@ -45,75 +41,13 @@ pub unsafe fn __rust_start_panic(_payload: &mut dyn PanicPayload) -> u32 {
zkvm::zkvm_set_abort_message(_payload);
}
unsafe {
abort();
unsafe extern "Rust" {
// This is defined in std::rt.
#[rustc_std_internal_symbol]
safe fn __rust_abort() -> !;
}
cfg_if::cfg_if! {
if #[cfg(any(unix, target_os = "solid_asp3"))] {
unsafe fn abort() -> ! {
unsafe { libc::abort(); }
}
} else if #[cfg(any(target_os = "hermit",
all(target_vendor = "fortanix", target_env = "sgx"),
target_os = "xous",
target_os = "uefi",
))] {
unsafe fn abort() -> ! {
// call std::sys::abort_internal
unsafe extern "C" {
pub fn __rust_abort() -> !;
}
unsafe { __rust_abort(); }
}
} else if #[cfg(all(windows, not(miri)))] {
// On Windows, use the processor-specific __fastfail mechanism. In Windows 8
// and later, this will terminate the process immediately without running any
// in-process exception handlers. In earlier versions of Windows, this
// sequence of instructions will be treated as an access violation,
// terminating the process but without necessarily bypassing all exception
// handlers.
//
// https://docs.microsoft.com/en-us/cpp/intrinsics/fastfail
//
// Note: this is the same implementation as in std's `abort_internal`
unsafe fn abort() -> ! {
#[allow(unused)]
const FAST_FAIL_FATAL_APP_EXIT: usize = 7;
cfg_if::cfg_if! {
if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
unsafe {
core::arch::asm!("int $$0x29", in("ecx") FAST_FAIL_FATAL_APP_EXIT, options(noreturn, nostack));
}
} else if #[cfg(all(target_arch = "arm", target_feature = "thumb-mode"))] {
unsafe {
core::arch::asm!(".inst 0xDEFB", in("r0") FAST_FAIL_FATAL_APP_EXIT, options(noreturn, nostack));
}
} else if #[cfg(any(target_arch = "aarch64", target_arch = "arm64ec"))] {
unsafe {
core::arch::asm!("brk 0xF003", in("x0") FAST_FAIL_FATAL_APP_EXIT, options(noreturn, nostack));
}
} else {
core::intrinsics::abort();
}
}
}
} else if #[cfg(target_os = "teeos")] {
mod teeos {
unsafe extern "C" {
pub fn TEE_Panic(code: u32) -> !;
}
}
unsafe fn abort() -> ! {
unsafe { teeos::TEE_Panic(1); }
}
} else {
unsafe fn abort() -> ! {
core::intrinsics::abort();
}
}
}
__rust_abort()
}
// This... is a bit of an oddity. The tl;dr; is that this is required to link

View file

@ -5,20 +5,16 @@
use alloc::boxed::Box;
use core::any::Any;
unsafe extern "Rust" {
// This is defined in std::rt
#[rustc_std_internal_symbol]
safe fn __rust_abort() -> !;
}
pub(crate) unsafe fn cleanup(_ptr: *mut u8) -> Box<dyn Any + Send> {
unsafe extern "C" {
fn __rust_abort() -> !;
}
unsafe {
__rust_abort();
}
__rust_abort()
}
pub(crate) unsafe fn panic(_data: Box<dyn Any + Send>) -> u32 {
unsafe extern "C" {
fn __rust_abort() -> !;
}
unsafe {
__rust_abort();
}
__rust_abort()
}

View file

@ -26,6 +26,13 @@ use crate::sync::Once;
use crate::thread::{self, main_thread};
use crate::{mem, panic, sys};
// This function is needed by the panic runtime.
#[cfg(not(test))]
#[rustc_std_internal_symbol]
fn __rust_abort() {
crate::process::abort();
}
// Prints to the "panic output", depending on the platform this may be:
// - the standard error output
// - some dedicated platform specific output
@ -47,7 +54,7 @@ macro_rules! rtabort {
($($t:tt)*) => {
{
rtprintpanic!("fatal runtime error: {}, aborting\n", format_args!($($t)*));
crate::sys::abort_internal();
crate::process::abort();
}
}
}

View file

@ -43,15 +43,6 @@ pub fn abort_internal() -> ! {
unsafe { hermit_abi::abort() }
}
// This function is needed by the panic runtime. The symbol is named in
// pre-link args for the target specification, so keep that in sync.
#[cfg(not(test))]
#[unsafe(no_mangle)]
// NB. used by both libunwind and libpanic_abort
pub extern "C" fn __rust_abort() {
abort_internal();
}
// SAFETY: must be called only once during runtime initialization.
// NOTE: this is not guaranteed to run, for example when Rust code is called externally.
pub unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) {

View file

@ -112,11 +112,14 @@ pub fn abort_internal() -> ! {
abi::usercalls::exit(true)
}
// This function is needed by the panic runtime. The symbol is named in
// This function is needed by libunwind. The symbol is named in
// pre-link args for the target specification, so keep that in sync.
// Note: contrary to the `__rust_abort` in `crate::rt`, this uses `no_mangle`
// because it is actually used from C code. Because symbols annotated with
// #[rustc_std_internal_symbol] get mangled, this will not lead to linker
// conflicts.
#[cfg(not(test))]
#[unsafe(no_mangle)]
// NB. used by both libunwind and libpanic_abort
pub extern "C" fn __rust_abort() {
abort_internal();
}

View file

@ -161,14 +161,6 @@ pub fn abort_internal() -> ! {
core::intrinsics::abort();
}
// This function is needed by the panic runtime. The symbol is named in
// pre-link args for the target specification, so keep that in sync.
#[cfg(not(test))]
#[unsafe(no_mangle)]
pub extern "C" fn __rust_abort() {
abort_internal();
}
/// Disable access to BootServices if `EVT_SIGNAL_EXIT_BOOT_SERVICES` is signaled
extern "efiapi" fn exit_boot_service_handler(_e: r_efi::efi::Event, _ctx: *mut crate::ffi::c_void) {
uefi::env::disable_boot_services();

View file

@ -328,8 +328,13 @@ pub fn dur2timeout(dur: Duration) -> u32 {
/// Use `__fastfail` to abort the process
///
/// This is the same implementation as in libpanic_abort's `__rust_start_panic`. See
/// that function for more information on `__fastfail`
/// In Windows 8 and later, this will terminate the process immediately without
/// running any in-process exception handlers. In earlier versions of Windows,
/// this sequence of instructions will be treated as an access violation,
/// terminating the process but without necessarily bypassing all exception
/// handlers.
///
/// https://docs.microsoft.com/en-us/cpp/intrinsics/fastfail
#[cfg(not(miri))] // inline assembly does not work in Miri
pub fn abort_internal() -> ! {
unsafe {

View file

@ -1,5 +1,7 @@
#![forbid(unsafe_op_in_unsafe_fn)]
use crate::os::xous::ffi::exit;
pub mod os;
#[path = "../unsupported/pipe.rs"]
pub mod pipe;
@ -9,3 +11,7 @@ pub mod time;
#[path = "../unsupported/common.rs"]
mod common;
pub use common::*;
pub fn abort_internal() -> ! {
exit(101);
}

View file

@ -62,14 +62,6 @@ mod c_compat {
}
exit(unsafe { main() });
}
// This function is needed by the panic runtime. The symbol is named in
// pre-link args for the target specification, so keep that in sync.
#[unsafe(no_mangle)]
// NB. used by both libunwind and libpanic_abort
pub extern "C" fn __rust_abort() -> ! {
exit(101);
}
}
pub fn errno() -> i32 {