note that this is all unstable internal details
[web.git] / ralf / _posts / 2019-11-25-how-to-panic-in-rust.md
index 0a9d2ba21b7bba82c4ba7cf740acde09360788a6..3f5e2f13ed077a6b8518071f9f2ef30b4de24c6f 100644 (file)
@@ -18,6 +18,9 @@ There [are still some rough edges](https://github.com/rust-lang/miri/issues?q=is
 The purpose of this post is to document the high-level structure and the relevant interfaces that come into play on the Rust side of this.
 The actual mechanism of unwinding is a totally different matter (and one that I am not qualified to speak about).
 
+*Note:* This post describes panicking as of [this commit](https://github.com/rust-lang/rust/commit/7d761fe0462ba0f671a237d0bb35e3579b8ba0e8).
+Many of the interfaces described here are unstable internal details of libstd, and subject to change any time.
+
 ## High-level structure
 
 When trying to figure out how panicking works by reading the code in libstd, one can easily get lost in the maze.
@@ -71,7 +74,7 @@ On top of the panic *runtime* interface, libstd implements the default Rust pani
 
 #### `rust_panic_with_hook`
 
-The key function that everything passes through is [`rust_panic_with_hook`](https://github.com/rust-lang/rust/blob/7d761fe0462ba0f671a237d0bb35e3579b8ba0e8/src/libstd/panicking.rs#L435-L437):
+The key function that almost everything passes through is [`rust_panic_with_hook`](https://github.com/rust-lang/rust/blob/7d761fe0462ba0f671a237d0bb35e3579b8ba0e8/src/libstd/panicking.rs#L435-L437):
 {% highlight rust %}
 fn rust_panic_with_hook(
     payload: &mut dyn BoxMeUp,
@@ -96,7 +99,7 @@ The `'static` bound is quite well hidden there, but after a while I realized tha
 
 #### libstd panicking entry points
 
-`rust_panic_with_hook` is a private function to `std::panicking`; the module provides three separate entry points on top of this central function:
+`rust_panic_with_hook` is a private function to `std::panicking`; the module provides three entry points on top of this central function, and one that circumvents it:
 
 * the [default panic handler implementation](https://github.com/rust-lang/rust/blob/7d761fe0462ba0f671a237d0bb35e3579b8ba0e8/src/libstd/panicking.rs#L301), backing (as we will see) panics from `core::panic!` and built-in panics (from arithmetic overflow or out-of-bounds array/slice indexing).
   This obtains as input a [`PanicInfo` ](https://doc.rust-lang.org/core/panic/struct.PanicInfo.html), and it has to turn that into arguments for `rust_panic_with_hook`.
@@ -119,6 +122,11 @@ The `'static` bound is quite well hidden there, but after a while I realized tha
     In particular, a panic hook that looks at the `message` field of the `PanicData` it is passed will *not* be able to see the message in a `std::panic!("do panic")`, but it *will* see the message in a `std::panic!("panic with data: {}", data)` as the latter passes through `begin_panic_fmt` instead.
   That seems quite surprising. (But also note that `PanicData::message()` is not stable yet.)
 
+* [`update_count_then_panic`](https://github.com/rust-lang/rust/blob/7d761fe0462ba0f671a237d0bb35e3579b8ba0e8/src/libstd/panicking.rs#L488) is the odd one out: this entry point backs [`resume_unwind`](https://doc.rust-lang.org/nightly/std/panic/fn.resume_unwind.html), and it actually does *not* call the panic hook.
+  Instead, it dispatches to the panic runtime immediately.
+  Like, `begin_panic`, it lets the caller pick an arbitrary payload.
+  Unlike `begin_panic`, the caller is responsible for boxing and unsizing the payload; `update_count_then_panic` just forwards that pretty much verbatim to the panic runtime.
+
 ## Panic Handler
 
 All of the `std::panic!` machinery is really useful, but it relies on heap allocations through `Box` which is not always available.