diff --git a/src/libpanic_abort/lib.rs b/src/libpanic_abort/lib.rs index db7c250e21157..ebc57860b9d4a 100644 --- a/src/libpanic_abort/lib.rs +++ b/src/libpanic_abort/lib.rs @@ -17,18 +17,11 @@ #![feature(panic_runtime)] #![feature(staged_api)] #![feature(rustc_attrs)] +#![feature(raw)] -// Rust's "try" function, but if we're aborting on panics we just call the -// function as there's nothing else we need to do here. #[rustc_std_internal_symbol] -pub unsafe extern "C" fn __rust_maybe_catch_panic( - f: fn(*mut u8), - data: *mut u8, - _data_ptr: *mut usize, - _vtable_ptr: *mut usize, -) -> u32 { - f(data); - 0 +pub unsafe extern "C" fn __rust_cleanup(_: *mut u8) -> core::raw::TraitObject { + unreachable!() } // "Leak" the payload and shim to the relevant abort on the platform in diff --git a/src/libpanic_unwind/dummy.rs b/src/libpanic_unwind/dummy.rs index 8675632638712..30593d3b88af9 100644 --- a/src/libpanic_unwind/dummy.rs +++ b/src/libpanic_unwind/dummy.rs @@ -6,9 +6,7 @@ use alloc::boxed::Box; use core::any::Any; use core::intrinsics; -pub fn payload() -> *mut u8 { - core::ptr::null_mut() -} +pub type Payload = *mut u8; pub unsafe fn cleanup(_ptr: *mut u8) -> Box { intrinsics::abort() diff --git a/src/libpanic_unwind/emcc.rs b/src/libpanic_unwind/emcc.rs index 9161d49959cf5..873135414bd9d 100644 --- a/src/libpanic_unwind/emcc.rs +++ b/src/libpanic_unwind/emcc.rs @@ -48,9 +48,7 @@ static EXCEPTION_TYPE_INFO: TypeInfo = TypeInfo { name: b"rust_panic\0".as_ptr(), }; -pub fn payload() -> *mut u8 { - ptr::null_mut() -} +pub type Payload = *mut u8; struct Exception { // This needs to be an Option because the object's lifetime follows C++ diff --git a/src/libpanic_unwind/gcc.rs b/src/libpanic_unwind/gcc.rs index 591ff9d7fdcaa..dd84a814f48b1 100644 --- a/src/libpanic_unwind/gcc.rs +++ b/src/libpanic_unwind/gcc.rs @@ -48,7 +48,6 @@ use alloc::boxed::Box; use core::any::Any; -use core::ptr; use crate::dwarf::eh::{self, EHAction, EHContext}; use libc::{c_int, uintptr_t}; @@ -83,9 +82,7 @@ pub unsafe fn panic(data: Box) -> u32 { } } -pub fn payload() -> *mut u8 { - ptr::null_mut() -} +pub type Payload = *mut u8; pub unsafe fn cleanup(ptr: *mut u8) -> Box { let exception = Box::from_raw(ptr as *mut Exception); diff --git a/src/libpanic_unwind/hermit.rs b/src/libpanic_unwind/hermit.rs index 2f53df2861d44..8ffb4bcd3df23 100644 --- a/src/libpanic_unwind/hermit.rs +++ b/src/libpanic_unwind/hermit.rs @@ -6,9 +6,7 @@ use alloc::boxed::Box; use core::any::Any; use core::ptr; -pub fn payload() -> *mut u8 { - ptr::null_mut() -} +pub type Payload = *mut u8; pub unsafe fn cleanup(_ptr: *mut u8) -> Box { extern "C" { diff --git a/src/libpanic_unwind/lib.rs b/src/libpanic_unwind/lib.rs index 6383ae39fb6db..60ddf70cea52f 100644 --- a/src/libpanic_unwind/lib.rs +++ b/src/libpanic_unwind/lib.rs @@ -22,20 +22,20 @@ #![feature(libc)] #![feature(nll)] #![feature(panic_unwind)] -#![feature(raw)] #![feature(staged_api)] #![feature(std_internals)] #![feature(unwind_attributes)] #![feature(abi_thiscall)] +#![feature(rustc_attrs)] +#![feature(raw)] #![panic_runtime] #![feature(panic_runtime)] use alloc::boxed::Box; -use core::intrinsics; -use core::mem; use core::panic::BoxMeUp; -use core::raw; +// If adding to this list, you should also look at libstd::panicking's identical +// list of Payload types and likely add to there as well. cfg_if::cfg_if! { if #[cfg(target_os = "emscripten")] { #[path = "emcc.rs"] @@ -69,28 +69,11 @@ extern "C" { mod dwarf; -// Entry point for catching an exception, implemented using the `try` intrinsic -// in the compiler. -// -// The interaction between the `payload` function and the compiler is pretty -// hairy and tightly coupled, for more information see the compiler's -// implementation of this. #[no_mangle] -pub unsafe extern "C" fn __rust_maybe_catch_panic( - f: fn(*mut u8), - data: *mut u8, - data_ptr: *mut usize, - vtable_ptr: *mut usize, -) -> u32 { - let mut payload = imp::payload(); - if intrinsics::r#try(f, data, &mut payload as *mut _ as *mut _) == 0 { - 0 - } else { - let obj = mem::transmute::<_, raw::TraitObject>(imp::cleanup(payload)); - *data_ptr = obj.data as usize; - *vtable_ptr = obj.vtable as usize; - 1 - } +pub unsafe extern "C" fn __rust_panic_cleanup(payload: *mut u8) -> core::raw::TraitObject { + let payload = payload as *mut imp::Payload; + let payload = *(payload); + core::mem::transmute(imp::cleanup(payload)) } // Entry point for raising an exception, just delegates to the platform-specific diff --git a/src/libpanic_unwind/seh.rs b/src/libpanic_unwind/seh.rs index 6f507e85e742c..6f464c1ab680e 100644 --- a/src/libpanic_unwind/seh.rs +++ b/src/libpanic_unwind/seh.rs @@ -308,9 +308,7 @@ pub unsafe fn panic(data: Box) -> u32 { _CxxThrowException(throw_ptr, &mut THROW_INFO as *mut _ as *mut _); } -pub fn payload() -> [u64; 2] { - [0; 2] -} +pub type Payload = [u64; 2]; pub unsafe fn cleanup(payload: [u64; 2]) -> Box { mem::transmute(raw::TraitObject { data: payload[0] as *mut _, vtable: payload[1] as *mut _ }) diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 8b12aaaa7e2fd..f71849fae34fa 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -12,9 +12,8 @@ use core::panic::{BoxMeUp, Location, PanicInfo}; use crate::any::Any; use crate::fmt; use crate::intrinsics; -use crate::mem::{self, ManuallyDrop}; +use crate::mem::{self, ManuallyDrop, MaybeUninit}; use crate::process; -use crate::raw; use crate::sync::atomic::{AtomicBool, Ordering}; use crate::sys::stdio::panic_output; use crate::sys_common::backtrace::{self, RustBacktrace}; @@ -29,6 +28,31 @@ use crate::io::set_panic; #[cfg(test)] use realstd::io::set_panic; +// This must be kept in sync with the implementations in libpanic_unwind. +// +// This is *not* checked in anyway; the compiler does not allow us to use a +// type/macro/anything from panic_unwind, since we're then linking in the +// panic_unwind runtime even during -Cpanic=abort. +// +// Essentially this must be the type of `imp::Payload` in libpanic_unwind. +cfg_if::cfg_if! { + if #[cfg(not(feature = "panic_unwind"))] { + type Payload = (); + } else if #[cfg(target_os = "emscripten")] { + type Payload = *mut u8; + } else if #[cfg(target_arch = "wasm32")] { + type Payload = *mut u8; + } else if #[cfg(target_os = "hermit")] { + type Payload = *mut u8; + } else if #[cfg(all(target_env = "msvc", target_arch = "aarch64"))] { + type Payload = *mut u8; + } else if #[cfg(target_env = "msvc")] { + type Payload = [u64; 2]; + } else { + type Payload = *mut u8; + } +} + // Binary interface to the panic runtime that the standard library depends on. // // The standard library is tagged with `#![needs_panic_runtime]` (introduced in @@ -41,12 +65,9 @@ use realstd::io::set_panic; // hook up these functions, but it is not this day! #[allow(improper_ctypes)] extern "C" { - fn __rust_maybe_catch_panic( - f: fn(*mut u8), - data: *mut u8, - data_ptr: *mut usize, - vtable_ptr: *mut usize, - ) -> u32; + /// The payload ptr here is actually the same as the payload ptr for the try + /// intrinsic (i.e., is really `*mut [u64; 2]` or `*mut *mut u8`). + fn __rust_panic_cleanup(payload: *mut u8) -> core::raw::TraitObject; /// `payload` is actually a `*mut &mut dyn BoxMeUp` but that would cause FFI warnings. /// It cannot be `Box` because the other end of this call does not depend @@ -250,9 +271,9 @@ pub unsafe fn r#try R>(f: F) -> Result> } // We do some sketchy operations with ownership here for the sake of - // performance. We can only pass pointers down to - // `__rust_maybe_catch_panic` (can't pass objects by value), so we do all - // the ownership tracking here manually using a union. + // performance. We can only pass pointers down to `do_call` (can't pass + // objects by value), so we do all the ownership tracking here manually + // using a union. // // We go through a transition where: // @@ -263,7 +284,7 @@ pub unsafe fn r#try R>(f: F) -> Result> // * If the closure successfully returns, we write the return value into the // data's return slot. Note that `ptr::write` is used as it's overwriting // uninitialized data. - // * Finally, when we come back out of the `__rust_maybe_catch_panic` we're + // * Finally, when we come back out of the `try` intrinsic we're // in one of two states: // // 1. The closure didn't panic, in which case the return value was @@ -274,27 +295,24 @@ pub unsafe fn r#try R>(f: F) -> Result> // // Once we stack all that together we should have the "most efficient' // method of calling a catch panic whilst juggling ownership. - let mut any_data = 0; - let mut any_vtable = 0; let mut data = Data { f: ManuallyDrop::new(f) }; - let r = __rust_maybe_catch_panic( - do_call::, - &mut data as *mut _ as *mut u8, - &mut any_data, - &mut any_vtable, - ); + let mut payload: MaybeUninit = MaybeUninit::uninit(); - return if r == 0 { + let data_ptr = &mut data as *mut _ as *mut u8; + let payload_ptr = payload.as_mut_ptr() as *mut _; + return if intrinsics::r#try(do_call::, data_ptr, payload_ptr) == 0 { Ok(ManuallyDrop::into_inner(data.r)) } else { - update_panic_count(-1); - Err(mem::transmute(raw::TraitObject { - data: any_data as *mut _, - vtable: any_vtable as *mut _, - })) + Err(cleanup(payload.assume_init())) }; + unsafe fn cleanup(mut payload: Payload) -> Box { + let obj = crate::mem::transmute(__rust_panic_cleanup(&mut payload as *mut _ as *mut u8)); + update_panic_count(-1); + obj + } + fn do_call R, R>(data: *mut u8) { unsafe { let data = data as *mut Data;