diff --git a/src/libpanic_unwind/emcc.rs b/src/libpanic_unwind/emcc.rs index 9d3fe5254f8..61f33fd4d5d 100644 --- a/src/libpanic_unwind/emcc.rs +++ b/src/libpanic_unwind/emcc.rs @@ -52,22 +52,32 @@ pub fn payload() -> *mut u8 { ptr::null_mut() } +struct Exception { + data: Option>, +} + pub unsafe fn cleanup(ptr: *mut u8) -> Box { assert!(!ptr.is_null()); - let adjusted_ptr = __cxa_begin_catch(ptr as *mut libc::c_void); - let ex = ptr::read(adjusted_ptr as *mut _); + let adjusted_ptr = __cxa_begin_catch(ptr as *mut libc::c_void) as *mut Exception; + let ex = (*adjusted_ptr).data.take(); __cxa_end_catch(); - ex + ex.unwrap() } pub unsafe fn panic(data: Box) -> u32 { let sz = mem::size_of_val(&data); - let exception = __cxa_allocate_exception(sz); + let exception = __cxa_allocate_exception(sz) as *mut Exception; if exception.is_null() { return uw::_URC_FATAL_PHASE1_ERROR as u32; } - ptr::write(exception as *mut _, data); - __cxa_throw(exception as *mut _, &EXCEPTION_TYPE_INFO, ptr::null_mut()); + ptr::write(exception, Exception { data: Some(data) }); + __cxa_throw(exception as *mut _, &EXCEPTION_TYPE_INFO, exception_cleanup); + + extern "C" fn exception_cleanup(ptr: *mut libc::c_void) { + unsafe { + ptr::drop_in_place(ptr as *mut Exception); + } + } } #[lang = "eh_personality"] @@ -89,7 +99,7 @@ extern "C" { fn __cxa_throw( thrown_exception: *mut libc::c_void, tinfo: *const TypeInfo, - dest: *mut libc::c_void, + dest: extern "C" fn(*mut libc::c_void), ) -> !; fn __gxx_personality_v0( version: c_int,