r[panic]
r[panic.intro] Rust provides a mechanism to prevent a function from returning normally, and instead “panic,” which is a response to an error condition that is typically not expected to be recoverable within the context in which the error is encountered.
r[panic.lang-ops] Some language constructs, such as out-of-bounds array indexing, panic automatically.
r[panic.control] There are also language features that provide a level of control over panic behavior:
[!NOTE] The standard library provides the capability to explicitly panic via the [
panic!
macro][panic!].
r[panic.panic_handler]
panic_handler
attributer[panic.panic_handler.intro] The panic_handler
attribute can be applied to a function to define the behavior of panics.
r[panic.panic_handler.allowed-positions] The panic_handler
attribute can only be applied to a function with signature fn(&PanicInfo) -> !
.
[!NOTE] The
PanicInfo
struct contains information about the location of the panic.
r[panic.panic_handler.unique] There must be a single panic_handler
function in the dependency graph.
Below is shown a panic_handler
function that logs the panic message and then halts the thread.
#![no_std] use core::fmt::{self, Write}; use core::panic::PanicInfo; struct Sink { // .. # _0: (), } # # impl Sink { # fn new() -> Sink { Sink { _0: () }} # } # # impl fmt::Write for Sink { # fn write_str(&mut self, _: &str) -> fmt::Result { Ok(()) } # } #[panic_handler] fn panic(info: &PanicInfo) -> ! { let mut sink = Sink::new(); // logs "panicked at '$reason', src/main.rs:27:4" to some `sink` let _ = writeln!(sink, "{}", info); loop {} }
r[panic.panic_handler.std]
r[panic.panic_handler.std.kinds] std
provides two different panic handlers:
unwind
--- unwinds the stack and is potentially recoverable.abort
---- aborts the process and is non-recoverable.Not all targets may provide the unwind
handler.
[!NOTE] The panic handler used when linking with
std
can be set with the-C panic
CLI flag. The default for most targets isunwind
.The standard library's panic behavior can be modified at runtime with the [
std::panic::set_hook
] function.
r[panic.panic_handler.std.no_std] Linking a no_std
binary, dylib, cdylib, or staticlib will require specifying your own panic handler.
r[panic.strategy]
r[panic.strategy.intro] The panic strategy defines the kind of panic behavior that a crate is built to support.
[!NOTE] The panic strategy can be chosen in
rustc
with the-C panic
CLI flag.When generating a binary, dylib, cdylib, or staticlib and linking with
std
, the-C panic
CLI flag also influences which panic handler is used.
[!NOTE] When compiling code with the
abort
panic strategy, the optimizer may assume that unwinding across Rust frames is impossible, which can result in both code-size and runtime speed improvements.
[!NOTE] See [link.unwinding] for restrictions on linking crates with different panic strategies. An implication is that crates built with the
unwind
strategy can use theabort
panic handler, but theabort
strategy cannot use theunwind
panic handler.
r[panic.unwind]
r[panic.unwind.intro] Panicking may either be recoverable or non-recoverable, though it can be configured (by choosing a non-unwinding panic handler) to always be non-recoverable. (The converse is not true: the unwind
handler does not guarantee that all panics are recoverable, only that panicking via the panic!
macro and similar standard library mechanisms is recoverable.)
r[panic.unwind.destruction] When a panic occurs, the unwind
handler “unwinds” Rust frames, just as C++'s throw
unwinds C++ frames, until the panic reaches the point of recovery (for instance at a thread boundary). This means that as the panic traverses Rust frames, live objects in those frames that implement Drop
will have their drop
methods called. Thus, when normal execution resumes, no-longer-accessible objects will have been “cleaned up” just as if they had gone out of scope normally.
[!NOTE] As long as this guarantee of resource-cleanup is preserved, “unwinding” may be implemented without actually using the mechanism used by C++ for the target platform.
[!NOTE] The standard library provides two mechanisms for recovering from a panic, [
std::panic::catch_unwind
] (which enables recovery within the panicking thread) and [std::thread::spawn
] (which automatically sets up panic recovery for the spawned thread so that other threads may continue running).
r[panic.unwind.ffi]
r[panic.unwind.ffi.intro] It is possible to unwind across FFI boundaries using an appropriate ABI declaration. While useful in certain cases, this creates unique opportunities for undefined behavior, especially when multiple language runtimes are involved.
r[panic.unwind.ffi.undefined] Unwinding with the wrong ABI is undefined behavior:
"C"
, "system"
, etc. (For example, this case occurs when such a function written in C++ throws an exception that is uncaught and propagates to Rust.)extern
function that unwinds (with extern "C-unwind"
or another ABI that permits unwinding) from code that does not support unwinding, such as code compiled with GCC or Clang using -fno-exceptions
r[panic.unwind.ffi.catch-foreign] Catching a foreign unwinding operation (such as a C++ exception) using [std::panic::catch_unwind
], [std::thread::JoinHandle::join
], or by letting it propagate beyond the Rust main()
function or thread root will have one of two behaviors, and it is unspecified which will occur:
Result::Err
] containing an opaque type.[!NOTE] Rust code compiled or linked with a different instance of the Rust standard library counts as a “foreign exception” for the purpose of this guarantee. Thus, a library that uses
panic!
and is linked against one version of the Rust standard library, invoked from an application that uses a different version of the standard library, may cause the entire application to abort even if the library is only used within a child thread.
r[panic.unwind.ffi.dispose-panic] There are currently no guarantees about the behavior that occurs when a foreign runtime attempts to dispose of, or rethrow, a Rust panic
payload. In other words, an unwind originated from a Rust runtime must either lead to termination of the process or be caught by the same runtime.