• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #![allow(missing_docs)]
2 
3 use core::mem;
4 
prevent_unwind<F, R>(label: &'static str, foreign_call: F) -> R where F: FnOnce() -> R,5 pub fn prevent_unwind<F, R>(label: &'static str, foreign_call: F) -> R
6 where
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 
30 struct Guard {
31     label: &'static str,
32 }
33 
34 impl Drop for Guard {
35     #[cold]
drop(&mut self)36     fn drop(&mut self) {
37         panic!("panic in ffi function {}, aborting.", self.label);
38     }
39 }
40