blob: 960dd49ad542c9868290c42e2adb918910a6f9b3 [file] [log] [blame] [view]
# 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 Hitchhikers 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 Hitchhikers 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`.