1#![allow(missing_docs)] 2 3use core::mem; 4 5pub fn prevent_unwind<F, R>(label: &'static str, foreign_call: F) -> R 6where 7 F: FnOnce() -> R, 8{ 9 // Goal is to make it impossible to propagate a panic across the C interface 10 // of an extern "Rust" function, which would be Undefined Behavior. We 11 // transform such panicks into a deterministic abort instead. When cxx is 12 // built in an application using panic=abort, this guard object is compiled 13 // out because its destructor is statically unreachable. When built with 14 // panic=unwind, an unwind from the foreign call will attempt to drop the 15 // guard object leading to a double panic, which is defined by Rust to 16 // abort. In no_std programs, on most platforms the current mechanism for 17 // this is for core::intrinsics::abort to invoke an invalid instruction. On 18 // Unix, the process will probably terminate with a signal like SIGABRT, 19 // SIGILL, SIGTRAP, SIGSEGV or SIGBUS. The precise behaviour is not 20 // guaranteed and not stable, but is safe. 21 let guard = Guard { label }; 22 23 let ret = foreign_call(); 24 25 // If we made it here, no uncaught panic occurred during the foreign call. 26 mem::forget(guard); 27 ret 28} 29 30struct Guard { 31 label: &'static str, 32} 33 34impl Drop for Guard { 35 #[cold] 36 fn drop(&mut self) { 37 panic!("panic in ffi function {}, aborting.", self.label); 38 } 39} 40