blob: 5f49458d1b6f431960631b6dde662317eef679aa [file] [log] [blame] [view]
# Panics and Exceptions in C++/Rust FFI bindings
SUMMARY: Crubit currently requires `-fno-exceptions`, and converts unwinding
panics into aborts.
## Unwinding and Aborting
> "Alright so I'm panicking, what else is there to do?" \
> -- "The Hitchhiker’s Guide to the Galaxy" by Douglas Adams
Rust and C++ both support a form of unwinding exception/panic, where ordinary
control flow is terminated, and instead control proceeds up the stack, calling
destructors along the way, until it is caught, converted to a termination, or
completely unwinds the stack (which also leads to termination).
This has a performance cost (in that data must be managed soundly, destroyed if
appropriate, in case of unwinding), and a code complexity cost (in that unsafe
code must handle unexpected control flow edges soundly), so implementations of
both languages allow for unwinding to be disabled, in favor of immediate process
termination:
* Rust:
[`-Cpanic=abort`](https://doc.rust-lang.org/rustc/codegen-options/index.html#panic)
* C++
[`-fno-exceptions`](https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-fexceptions)
Crubit, and any FFI, will work if unwinding is disabled for both sides of the
FFI boundary. But if it is enabled for one or both sides, and an exception or
panic unwinds past an FFI boundary, we need special support to ensure that the
behavior is defined.
## Supported Configurations
> "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
**Rust:** Rust: Crubit can create bindings for libraries built with either
`-Cpanic=abort` or `-Cpanic=unwind`.
If a panic unwinds past a Crubit FFI boundary, the process will terminate
(on rustc nightly[^terminate_requirements]), with
the **sole** exception of `extern "C-unwind"` functions. If you define an
`extern "C-unwind"` function, you must ensure that it is only called by C++ code
which enables exceptions. This responsibility is left to the caller.
**C++:** Crubit can create bindings for libraries built with `-fno-exceptions`.
We do not generate `extern "C-unwind"` interfaces which could propagate a C++
exception, and the behavior is undefined if an exception propagates past a
Crubit FFI boundary. (See b/200067087 for catching this at compile time.)
<!-- TODO(b/200067087): fail when exceptions are enabled, document above. -->
[^terminate_requirements]: We use the behavior of
https://doc.rust-lang.org/nomicon/ffi.html#ffi-and-unwinding
to cause a crash. However, this is not yet
incorporated into a stable Rust release, and requires
nightly.
<!-- TODO(b/254049425): remove above note once crash reaches stable. -->