| # Panics and Exceptions in C++/Rust FFI bindings |
| |
| This document explains what Crubit's `rs_bindings_from_cc` and |
| `cc_bindings_from_rs` tools do to handle Rust panics and C++ exceptions. |
| |
| ## Aborting on panic |
| |
| > "Alright so I'm panicking, what else is there to do?" \ |
| > -- "The Hitchhiker’s Guide to the Galaxy" by Douglas Adams |
| |
| Rust libraries built with |
| [`-Cpanic=abort`](https://doc.rust-lang.org/rustc/codegen-options/index.html#panic) |
| terminate their process upon panic and there isn't much else to do. Similarly, |
| C++ libraries built with Clang's |
| [`-fno-exceptions`](https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-fexceptions) |
| flag terminate the process when a C++ exception is thrown. |
| |
| In build environments that use the flags above, Rust panics and C++ exceptions |
| don't unwind the callstack looking for appropriate handlers. This means that |
| bindings generated by Crubit's `rs_bindings_from_cc` and `cc_bindings_from_rs` |
| tools don't need to do anything special to handle panics and/or exceptions. In |
| particular, Rust calls into C++ (and C++ calls into Rust) can just use the "C" |
| ABI and assume that no panics and no exceptions will ever need to unwind across |
| the FFI boundary. |
| |
| Currently Crubit-generated bindings only support `-Cpanic=abort`, |
| `-fno-exceptions` environment. See |
| [the "Exceptions" section in the Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html#Exceptions) |
| for discussion of some of the pros and cons of an `-fno-exceptions` environment. |
| |
| ## Cross-language unwinding |
| |
| TODO(b/254049425): Add support for cross-FFI unwinding of Rust panics and C++ |
| exceptions. |
| |
| > "Who said anything about panicking?" snapped Arthur. "This is still just the |
| > culture shock. You wait till I've settled down into the situation and found my |
| > bearings. Then I'll start panicking." \ |
| > -- "The Hitchhiker’s Guide to the Galaxy" by Douglas Adams |
| |
| Crubit doesn't currently support unwinding of Rust panics or C++ exceptions |
| across the FFI boundary. In other words, the generated bindings are only safe |
| when `-Cpanic=abort` and `-fno-exceptions` are used - other configurations may |
| lead to Undefined Behavior: |
| |
| * C++ exception unwinding through Rust frames leads to Undefined Behavior |
| (based on |
| [this part](https://rust-lang.github.io/rfcs/2945-c-unwind-abi.html#changes-to-the-behavior-of-existing-abi-strings) |
| of RFC 2945). |
| |
| * Rust panic unwinding through C++ frames leads to Undefined Behavior. Note |
| that [RFC 2945](https://rust-lang.github.io/rfcs/2945-c-unwind-abi.html) |
| defines some of that behavior: "with the `panic=unwind` runtime, `panic!` |
| will cause an abort if it would otherwise "escape" from a function defined |
| with `extern "C"`." |
| |
| Below is an incomplete, tentative list of steps needed to add Crubit support for |
| cross-language unwinding of panics and exceptions: |
| |
| * Support building Crubit's automated tests with `-Cpanic=unwind` and/or |
| `-fexceptions`. Use this support to add test coverage for: |
| |
| - Propagating a Rust panic across C++ frames and catching it in another |
| Rust frame. |
| - Propagating a C++ exception across Rust frames and catching it in |
| another C++ frame. |
| |
| * If one or both languages don't abort on unwind, then modify the generated |
| Rust code to use the new `"C-unwind"` ABI string proposed by |
| [RFC 2945](https://rust-lang.github.io/rfcs/2945-c-unwind-abi.html) (instead |
| of using the old `"C"` ABI string): |
| |
| - `rs_bindings_from_cc` should use `"C-unwind"` ABI when declaring C++ |
| thunks in `mod detail` in the generated `..._rs_api.rs` |
| - `cc_bindings_from_rs` should use `"C-unwind"` ABI when defining C++ |
| thunks in `..._cc_api_impl.rs` |
| |
| * Investigate if Crubit needs to modify the generated C++ code. For example: |
| |
| - C++ thunk definitions generated by `rs_bindings_from_cc` in |
| `..._rs_api_impl.cc`. |
| - C++ declarations generated by `cc_bindings_from_rs` in `..._cc_api.h`. |