Skip to content

deduplicate abort implementations #139103

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
May 17, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
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.
  • Loading branch information
joboet committed May 15, 2025
commit b7f2cd3a2b1606934018cc64bac52bb887ea892a
1 change: 0 additions & 1 deletion library/Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,6 @@ name = "panic_abort"
version = "0.0.0"
dependencies = [
"alloc",
"cfg-if",
"compiler_builtins",
"core",
"libc",
Expand Down
7 changes: 4 additions & 3 deletions library/panic_abort/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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" }
76 changes: 5 additions & 71 deletions library/panic_abort/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down
20 changes: 8 additions & 12 deletions library/panic_unwind/src/hermit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
9 changes: 8 additions & 1 deletion library/std/src/rt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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();
}
}
}
Expand Down
9 changes: 0 additions & 9 deletions library/std/src/sys/pal/hermit/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
7 changes: 5 additions & 2 deletions library/std/src/sys/pal/sgx/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Comment on lines +117 to +120
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could they get different symbol names? Having the same extern signature reused but distinguished by attributes is a bit tricky.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

__rust_abort is the obvious name for the symbol shared between panic_abort and std, so I'm a bit hesitant about changing that. Changing the SGX symbol seems better, but it's a lot of effort as it requires changing libunwind as well; I don't really think it's worth it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Symbols marked as #[rustc_std_internal_symbol] don't really need the __rust_ prefix anymore now that we do symbol mangling for them too.

#[cfg(not(test))]
#[unsafe(no_mangle)]
// NB. used by both libunwind and libpanic_abort
pub extern "C" fn __rust_abort() {
abort_internal();
}
Expand Down
8 changes: 0 additions & 8 deletions library/std/src/sys/pal/uefi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
9 changes: 7 additions & 2 deletions library/std/src/sys/pal/windows/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// 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.
/// In Windows 8 and later, this will terminate the process immediately,
/// bypassing all 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.

Let's use the same verb both times, otherwise this is unnecessarily confusing since it uses "without" twice to actually make statements that are opposites of each other.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've rephrased the comment a bit to make it even clearer.

///
/// https://docs.microsoft.com/en-us/cpp/intrinsics/fastfail
#[cfg(not(miri))] // inline assembly does not work in Miri
pub fn abort_internal() -> ! {
unsafe {
Expand Down
6 changes: 6 additions & 0 deletions library/std/src/sys/pal/xous/mod.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -9,3 +11,7 @@ pub mod time;
#[path = "../unsupported/common.rs"]
mod common;
pub use common::*;

pub fn abort_internal() -> ! {
exit(101);
}
8 changes: 0 additions & 8 deletions library/std/src/sys/pal/xous/os.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down