diff options
Diffstat (limited to 'vendor/cxx/src/unwind.rs')
-rw-r--r-- | vendor/cxx/src/unwind.rs | 39 |
1 files changed, 39 insertions, 0 deletions
diff --git a/vendor/cxx/src/unwind.rs b/vendor/cxx/src/unwind.rs new file mode 100644 index 000000000..18852da71 --- /dev/null +++ b/vendor/cxx/src/unwind.rs @@ -0,0 +1,39 @@ +#![allow(missing_docs)] + +use core::mem; + +pub fn prevent_unwind<F, R>(label: &'static str, foreign_call: F) -> R +where + F: FnOnce() -> R, +{ + // Goal is to make it impossible to propagate a panic across the C interface + // of an extern "Rust" function, which would be Undefined Behavior. We + // transform such panicks into a deterministic abort instead. When cxx is + // built in an application using panic=abort, this guard object is compiled + // out because its destructor is statically unreachable. When built with + // panic=unwind, an unwind from the foreign call will attempt to drop the + // guard object leading to a double panic, which is defined by Rust to + // abort. In no_std programs, on most platforms the current mechanism for + // this is for core::intrinsics::abort to invoke an invalid instruction. On + // Unix, the process will probably terminate with a signal like SIGABRT, + // SIGILL, SIGTRAP, SIGSEGV or SIGBUS. The precise behaviour is not + // guaranteed and not stable, but is safe. + let guard = Guard { label }; + + let ret = foreign_call(); + + // If we made it here, no uncaught panic occurred during the foreign call. + mem::forget(guard); + ret +} + +struct Guard { + label: &'static str, +} + +impl Drop for Guard { + #[cold] + fn drop(&mut self) { + panic!("panic in ffi function {}, aborting.", self.label); + } +} |