unwinding/
panic.rs

1use alloc::boxed::Box;
2use core::any::Any;
3use core::mem::MaybeUninit;
4
5use crate::abi::*;
6#[cfg(feature = "panic-handler")]
7pub use crate::panic_handler::*;
8use crate::panicking::Exception;
9
10static CANARY: u8 = 0;
11
12#[repr(transparent)]
13struct RustPanic(Box<dyn Any + Send>, DropGuard);
14
15struct DropGuard;
16
17impl Drop for DropGuard {
18    fn drop(&mut self) {
19        #[cfg(feature = "panic-handler")]
20        {
21            drop_panic();
22        }
23        crate::util::abort();
24    }
25}
26
27#[repr(C)]
28struct ExceptionWithPayload {
29    exception: MaybeUninit<UnwindException>,
30    // See rust/library/panic_unwind/src/gcc.rs for the canary values
31    canary: *const u8,
32    payload: RustPanic,
33}
34
35unsafe impl Exception for RustPanic {
36    const CLASS: [u8; 8] = *b"MOZ\0RUST";
37
38    fn wrap(this: Self) -> *mut UnwindException {
39        Box::into_raw(Box::new(ExceptionWithPayload {
40            exception: MaybeUninit::uninit(),
41            canary: &CANARY,
42            payload: this,
43        })) as *mut UnwindException
44    }
45
46    unsafe fn unwrap(ex: *mut UnwindException) -> Self {
47        let ex = ex as *mut ExceptionWithPayload;
48        let canary = unsafe { core::ptr::addr_of!((*ex).canary).read() };
49        if !core::ptr::eq(canary, &CANARY) {
50            // This is a Rust exception but not generated by us.
51            #[cfg(feature = "panic-handler")]
52            {
53                foreign_exception();
54            }
55            crate::util::abort();
56        }
57        let ex = unsafe { Box::from_raw(ex) };
58        ex.payload
59    }
60}
61
62pub fn begin_panic(payload: Box<dyn Any + Send>) -> UnwindReasonCode {
63    crate::panicking::begin_panic(RustPanic(payload, DropGuard))
64}
65
66pub fn catch_unwind<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>> {
67    #[cold]
68    fn process_panic(p: Option<RustPanic>) -> Box<dyn Any + Send> {
69        match p {
70            None => {
71                #[cfg(feature = "panic-handler")]
72                {
73                    foreign_exception();
74                }
75                crate::util::abort();
76            }
77            Some(e) => {
78                #[cfg(feature = "panic-handler")]
79                {
80                    panic_caught();
81                }
82                core::mem::forget(e.1);
83                e.0
84            }
85        }
86    }
87    crate::panicking::catch_unwind(f).map_err(process_panic)
88}