Prevent foreign Rust exceptions from being caught
This commit is contained in:
parent
1ca6777c01
commit
e521a8d46b
1 changed files with 27 additions and 3 deletions
|
@ -38,12 +38,23 @@
|
||||||
|
|
||||||
use alloc::boxed::Box;
|
use alloc::boxed::Box;
|
||||||
use core::any::Any;
|
use core::any::Any;
|
||||||
|
use core::ptr;
|
||||||
|
|
||||||
use unwind as uw;
|
use unwind as uw;
|
||||||
|
|
||||||
|
// In case where multiple copies of std is compiled into a single binary,
|
||||||
|
// we use address of this static variable to distinguish an exception raised by
|
||||||
|
// this copy and some other copy (which needs to be treated as foreign exception).
|
||||||
|
static CANARY: u8 = 0;
|
||||||
|
|
||||||
|
// NOTE(nbdd0121)
|
||||||
|
// Once `c_unwind` feature is stabilized, there will be ABI stability requirement
|
||||||
|
// on this struct. The first two field must be `_Unwind_Exception` and `canary`,
|
||||||
|
// as it may be accessed by a different version of the std with a different compiler.
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
struct Exception {
|
struct Exception {
|
||||||
_uwe: uw::_Unwind_Exception,
|
_uwe: uw::_Unwind_Exception,
|
||||||
|
canary: *const u8,
|
||||||
cause: Box<dyn Any + Send>,
|
cause: Box<dyn Any + Send>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,6 +65,7 @@ pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
|
||||||
exception_cleanup,
|
exception_cleanup,
|
||||||
private: [0; uw::unwinder_private_data_size],
|
private: [0; uw::unwinder_private_data_size],
|
||||||
},
|
},
|
||||||
|
canary: &CANARY,
|
||||||
cause: data,
|
cause: data,
|
||||||
});
|
});
|
||||||
let exception_param = Box::into_raw(exception) as *mut uw::_Unwind_Exception;
|
let exception_param = Box::into_raw(exception) as *mut uw::_Unwind_Exception;
|
||||||
|
@ -75,10 +87,22 @@ pub unsafe fn cleanup(ptr: *mut u8) -> Box<dyn Any + Send> {
|
||||||
if (*exception).exception_class != rust_exception_class() {
|
if (*exception).exception_class != rust_exception_class() {
|
||||||
uw::_Unwind_DeleteException(exception);
|
uw::_Unwind_DeleteException(exception);
|
||||||
super::__rust_foreign_exception();
|
super::__rust_foreign_exception();
|
||||||
} else {
|
|
||||||
let exception = Box::from_raw(exception as *mut Exception);
|
|
||||||
exception.cause
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let exception = exception.cast::<Exception>();
|
||||||
|
// Just access the canary field, avoid accessing the entire `Exception` as
|
||||||
|
// it can be a foreign Rust exception.
|
||||||
|
let canary = ptr::addr_of!((*exception).canary).read();
|
||||||
|
if !ptr::eq(canary, &CANARY) {
|
||||||
|
// A foreign Rust exception, treat it slightly differently from other
|
||||||
|
// foreign exceptions, because call into `_Unwind_DeleteException` will
|
||||||
|
// call into `__rust_drop_panic` which produces a confusing
|
||||||
|
// "Rust panic must be rethrown" message.
|
||||||
|
super::__rust_foreign_exception();
|
||||||
|
}
|
||||||
|
|
||||||
|
let exception = Box::from_raw(exception as *mut Exception);
|
||||||
|
exception.cause
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rust's exception class identifier. This is used by personality routines to
|
// Rust's exception class identifier. This is used by personality routines to
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue