| 
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