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 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 #[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}