Skip to content

Commit aa87209

Browse files
committed
Prevent foreign Rust exceptions from being caught
1 parent 01af504 commit aa87209

File tree

1 file changed

+27
-3
lines changed
  • library/panic_unwind/src

1 file changed

+27
-3
lines changed

library/panic_unwind/src/gcc.rs

+27-3
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,23 @@
3838
3939
use alloc::boxed::Box;
4040
use core::any::Any;
41+
use core::ptr;
4142

4243
use unwind as uw;
4344

45+
// In case where multiple copies of std is compiled into a single binary,
46+
// we use address of this static variable to distinguish an exception raised by
47+
// this copy and some other copy (which needs to be treated as foreign exception).
48+
static CANARY: u8 = 0;
49+
50+
// NOTE(nbdd0121)
51+
// Once `c_unwind` feature is stabilized, there will be ABI stability requirement
52+
// on this struct. The first two field must be `_Unwind_Exception` and `canary`,
53+
// as it may be accessed by a different version of the std with a different compiler.
4454
#[repr(C)]
4555
struct Exception {
4656
_uwe: uw::_Unwind_Exception,
57+
canary: *const u8,
4758
cause: Box<dyn Any + Send>,
4859
}
4960

@@ -54,6 +65,7 @@ pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
5465
exception_cleanup,
5566
private: [0; uw::unwinder_private_data_size],
5667
},
68+
canary: &CANARY,
5769
cause: data,
5870
});
5971
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> {
7587
if (*exception).exception_class != rust_exception_class() {
7688
uw::_Unwind_DeleteException(exception);
7789
super::__rust_foreign_exception();
78-
} else {
79-
let exception = Box::from_raw(exception as *mut Exception);
80-
exception.cause
8190
}
91+
92+
let exception = exception.cast::<Exception>();
93+
// Just access the canary field, avoid accessing the entire `Exception` as
94+
// it can be a foreign Rust exception.
95+
let canary = ptr::addr_of!((*exception).canary).read();
96+
if !ptr::eq(canary, &CANARY) {
97+
// A foreign Rust exception, treat it slightly differently from other
98+
// foreign exceptions, because call into `_Unwind_DeleteException` will
99+
// call into `__rust_drop_panic` which produces a confusing
100+
// "Rust panic must be rethrown" message.
101+
super::__rust_foreign_exception();
102+
}
103+
104+
let exception = Box::from_raw(exception as *mut Exception);
105+
exception.cause
82106
}
83107

84108
// Rust's exception class identifier. This is used by personality routines to

0 commit comments

Comments
 (0)