|
49 | 49 | use alloc::boxed::Box;
|
50 | 50 | use core::any::Any;
|
51 | 51 | use core::mem::{self, ManuallyDrop};
|
| 52 | +use core::ptr; |
52 | 53 | use libc::{c_int, c_uint, c_void};
|
53 | 54 |
|
| 55 | +// NOTE(nbdd0121): The `canary` field will be part of stable ABI after `c_unwind` stabilization. |
| 56 | +#[repr(C)] |
54 | 57 | struct Exception {
|
| 58 | + // See `gcc.rs` on why this is present. We already have a static here so just use it. |
| 59 | + canary: *const _TypeDescriptor, |
| 60 | + |
55 | 61 | // This needs to be an Option because we catch the exception by reference
|
56 | 62 | // and its destructor is executed by the C++ runtime. When we take the Box
|
57 | 63 | // out of the exception, we need to leave the exception in a valid state
|
@@ -235,7 +241,7 @@ static mut TYPE_DESCRIPTOR: _TypeDescriptor = _TypeDescriptor {
|
235 | 241 | macro_rules! define_cleanup {
|
236 | 242 | ($abi:tt $abi2:tt) => {
|
237 | 243 | unsafe extern $abi fn exception_cleanup(e: *mut Exception) {
|
238 |
| - if let Exception { data: Some(b) } = e.read() { |
| 244 | + if let Exception { data: Some(b), .. } = e.read() { |
239 | 245 | drop(b);
|
240 | 246 | super::__rust_drop_panic();
|
241 | 247 | }
|
@@ -265,7 +271,7 @@ pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
|
265 | 271 | // The ManuallyDrop is needed here since we don't want Exception to be
|
266 | 272 | // dropped when unwinding. Instead it will be dropped by exception_cleanup
|
267 | 273 | // which is invoked by the C++ runtime.
|
268 |
| - let mut exception = ManuallyDrop::new(Exception { data: Some(data) }); |
| 274 | + let mut exception = ManuallyDrop::new(Exception { canary: &TYPE_DESCRIPTOR, data: Some(data) }); |
269 | 275 | let throw_ptr = &mut exception as *mut _ as *mut _;
|
270 | 276 |
|
271 | 277 | // This... may seems surprising, and justifiably so. On 32-bit MSVC the
|
@@ -321,8 +327,12 @@ pub unsafe fn cleanup(payload: *mut u8) -> Box<dyn Any + Send> {
|
321 | 327 | // __rust_try. This happens when a non-Rust foreign exception is caught.
|
322 | 328 | if payload.is_null() {
|
323 | 329 | super::__rust_foreign_exception();
|
324 |
| - } else { |
325 |
| - let exception = &mut *(payload as *mut Exception); |
326 |
| - exception.data.take().unwrap() |
327 | 330 | }
|
| 331 | + let exception = payload as *mut Exception; |
| 332 | + let canary = ptr::addr_of!((*exception).canary).read(); |
| 333 | + if !ptr::eq(canary, &TYPE_DESCRIPTOR) { |
| 334 | + // A foreign Rust exception. |
| 335 | + super::__rust_foreign_exception(); |
| 336 | + } |
| 337 | + (*exception).data.take().unwrap() |
328 | 338 | }
|
0 commit comments