@@ -718,17 +718,118 @@ void register(int (*f)(int (*)(int), int)) {
718718
719719No `transmute` required!
720720
721- ## FFI and panics
721+ ## FFI and unwinding
722722
723- It’s important to be mindful of `panic!`s when working with FFI. A `panic!`
724- across an FFI boundary is undefined behavior. If you’re writing code that may
725- panic, you should run it in a closure with [`catch_unwind`]:
723+ It’s important to be mindful of unwinding when working with FFI. Each
724+ non-`Rust` ABI comes in two variants, one with `-unwind` suffix and one without. If
725+ you expect Rust `panic`s or foreign (e.g. C++) exceptions to cross an FFI
726+ boundary, that boundary must use the appropriate `-unwind` ABI string (note
727+ that compiling with `panic=abort` will still cause `panic!` to immediately
728+ abort the process, regardless of which ABI is specified by the function that
729+ `panic`s).
730+
731+ Conversely, if you do not expect unwinding to cross an ABI boundary, use one of
732+ the non-`unwind` ABI strings (other than `Rust`, which always permits
733+ unwinding). If an unwinding operation does encounter an ABI boundary that is
734+ not permitted to unwind, the behavior depends on the source of the unwinding
735+ (Rust `panic` or a foreign exception):
736+
737+ * `panic` will cause the process to safely abort.
738+ * A foreign exception entering Rust will cause undefined behavior.
739+
740+ Note that the interaction of `catch_unwind` with foreign exceptions **is
741+ undefined**, as is the interaction of `panic` with foreign exception-catching
742+ mechanisms (notably C++'s `try`/`catch`).
743+
744+ ### Rust `panic` with `"C-unwind"`
745+
746+ <!-- ignore: using unstable feature -->
747+ ```rust,ignore
748+ #[no_mangle]
749+ extern "C-unwind" fn example() {
750+ panic!("Uh oh");
751+ }
752+ ```
753+
754+ This function (when compiled with ` panic=unwind ` ) is permitted to unwind C++
755+ stack frames.
756+
757+ ``` text
758+ [Rust function with `catch_unwind`, which stops the unwinding]
759+ |
760+ ...
761+ |
762+ [C++ frames]
763+ | ^
764+ | (calls) | (unwinding
765+ v | goes this
766+ [Rust function `example`] | way)
767+ | |
768+ +--- rust function panics --+
769+ ```
770+
771+ If the C++ frames have objects, their destructors will be called.
772+
773+ ### C++ ` throw ` with ` "C-unwind" `
774+
775+ <!-- ignore: using unstable feature -->
776+ ``` rust,ignore
777+ #[link(...)]
778+ extern "C-unwind" {
779+ // A C++ function that may throw an exception
780+ fn may_throw();
781+ }
782+
783+ #[no_mangle]
784+ extern "C-unwind" fn rust_passthrough() {
785+ let b = Box::new(5);
786+ unsafe { may_throw(); }
787+ println!("{:?}", &b);
788+ }
789+ ```
790+
791+ A C++ function with a ` try ` block may invoke ` rust_passthrough ` and ` catch ` an
792+ exception thrown by ` may_throw ` .
793+
794+ ``` text
795+ [C++ function with `try` block that invokes `rust_passthrough`]
796+ |
797+ ...
798+ |
799+ [Rust function `rust_passthrough`]
800+ | ^
801+ | (calls) | (unwinding
802+ v | goes this
803+ [C++ function `may_throw`] | way)
804+ | |
805+ +--- C++ function throws ----+
806+ ```
807+
808+ If ` may_throw ` does throw an exception, ` b ` will be dropped. Otherwise, ` 5 `
809+ will be printed.
810+
811+ ### ` panic ` can be stopped at an ABI boundary
812+
813+ ``` rust
814+ #[no_mangle]
815+ extern " C" fn assert_nonzero (input : u32 ) {
816+ assert! (input != 0 )
817+ }
818+ ```
819+
820+ If ` assert_nonzero ` is called with the argument ` 0 ` , the runtime is guaranteed
821+ to (safely) abort the process, whether or not compiled with ` panic=abort ` .
822+
823+ ### Catching ` panic ` preemptively
824+
825+ If you are writing Rust code that may panic, and you don't wish to abort the
826+ process if it panics, you must use [ ` catch_unwind ` ] :
726827
727828``` rust
728829use std :: panic :: catch_unwind;
729830
730831#[no_mangle]
731- pub extern fn oh_no() -> i32 {
832+ pub extern " C " fn oh_no () -> i32 {
732833 let result = catch_unwind (|| {
733834 panic! (" Oops!" );
734835 });
@@ -742,7 +843,7 @@ fn main() {}
742843```
743844
744845Please note that [ ` catch_unwind ` ] will only catch unwinding panics, not
745- those who abort the process. See the documentation of [ ` catch_unwind ` ]
846+ those that abort the process. See the documentation of [ ` catch_unwind ` ]
746847for more information.
747848
748849[ `catch_unwind` ] : ../std/panic/fn.catch_unwind.html
0 commit comments