blob: b69e958eb82f553602c2afdae004cf55be93c58d [file] [log] [blame] [edit]
use alloc::boxed::Box;
use core::any::Any;
use core::mem::MaybeUninit;
use crate::abi::*;
#[cfg(feature = "panic-handler")]
pub use crate::panic_handler::*;
use crate::panicking::Exception;
static CANARY: u8 = 0;
#[repr(transparent)]
struct RustPanic(Box<dyn Any + Send>, DropGuard);
struct DropGuard;
impl Drop for DropGuard {
fn drop(&mut self) {
#[cfg(feature = "panic-handler")]
{
drop_panic();
}
crate::util::abort();
}
}
#[repr(C)]
struct ExceptionWithPayload {
exception: MaybeUninit<UnwindException>,
// See rust/library/panic_unwind/src/gcc.rs for the canary values
canary: *const u8,
payload: RustPanic,
}
unsafe impl Exception for RustPanic {
const CLASS: [u8; 8] = *b"MOZ\0RUST";
fn wrap(this: Self) -> *mut UnwindException {
Box::into_raw(Box::new(ExceptionWithPayload {
exception: MaybeUninit::uninit(),
canary: &CANARY,
payload: this,
})) as *mut UnwindException
}
unsafe fn unwrap(ex: *mut UnwindException) -> Self {
let ex = ex as *mut ExceptionWithPayload;
let canary = unsafe { core::ptr::addr_of!((*ex).canary).read() };
if !core::ptr::eq(canary, &CANARY) {
// This is a Rust exception but not generated by us.
#[cfg(feature = "panic-handler")]
{
foreign_exception();
}
crate::util::abort();
}
let ex = unsafe { Box::from_raw(ex) };
ex.payload
}
}
pub fn begin_panic(payload: Box<dyn Any + Send>) -> UnwindReasonCode {
crate::panicking::begin_panic(RustPanic(payload, DropGuard))
}
pub fn catch_unwind<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>> {
#[cold]
fn process_panic(p: Option<RustPanic>) -> Box<dyn Any + Send> {
match p {
None => {
#[cfg(feature = "panic-handler")]
{
foreign_exception();
}
crate::util::abort();
}
Some(e) => {
#[cfg(feature = "panic-handler")]
{
panic_caught();
}
core::mem::forget(e.1);
e.0
}
}
}
crate::panicking::catch_unwind(f).map_err(process_panic)
}