Introduction
The choice between panic = "unwind" and panic = "abort" affects binary size, performance, and error handling capabilities. Combined with other settings, you can reduce Rust binaries from megabytes to kilobytes.
Key Concepts
Unwind (default)
- Runs destructors (Drop) when panicking
- Supports
catch_unwindfor panic recovery - Larger binary due to unwinding tables
- Required for libraries (let the caller decide)
Abort
- Terminates immediately on panic
- No destructors run
- Smaller binary
- Better for applications, embedded, WASM
toml[profile.release] panic = "abort"
Real World Context
Most production applications use panic = "abort" since panics indicate bugs that should crash the process. Libraries use unwind to give consumers flexibility. Embedded and WASM always use abort.
Deep Dive
Unwind Tables by Default (Rust 1.92)
Since Rust 1.92, unwind tables are emitted by default even with -Cpanic=abort on Linux. This means you get proper backtraces in crash reports even in abort mode — previously you would only see a bare abort with no stack trace.
To opt out (for minimal binary size):
toml[profile.release] panic = "abort" # Add to rustflags to disable unwind tables: # RUSTFLAGS="-C force-unwind-tables=no"
Binary Size Reduction Checklist
toml[profile.release] panic = "abort" # Remove unwinding code strip = true # Remove symbol table opt-level = "z" # Optimize for size lto = true # Dead code elimination codegen-units = 1 # Better DCE
Analyzing Binary Size
bashcargo install cargo-bloat cargo bloat --release --crates # Size by crate cargo bloat --release -n 20 # Top 20 functions by size
no_std for Minimal Binaries
rust#![no_std] #![no_main] #[panic_handler] fn panic(_: &core::panic::PanicInfo) -> ! { loop {} }
A no_std binary can be under 10 KB.
Common Pitfalls
- Using
panic = "abort"in a library crate — this forces all consumers to abort on panic. - Forgetting that
catch_unwinddoes not work withpanic = "abort". - Expecting
strip = trueto remove DWARF debug info — you also need to setdebug = false.
Best Practices
- Use
panic = "abort"for applications and"unwind"for libraries. - Use
cargo-bloatto find what is taking space before blindly applying settings. - Combine
lto + codegen-units = 1 + stripfor maximum dead-code elimination. - On Rust 1.92+, enjoy proper backtraces even with abort — only disable unwind tables if binary size is critical.
Summary
Panic strategy choice affects binary size and error recovery. Abort is smaller and simpler for applications. Since Rust 1.92, you get backtraces even with abort on Linux. Combine panic = abort, strip, LTO, and size optimization for the smallest binaries.
Code Examples
// catch_unwind: recovers from panics (requires panic="unwind")
use std::panic;
fn risky_operation() {
panic!("something went wrong");
}
fn main() {
let result = panic::catch_unwind(|| {
risky_operation();
});
match result {
Ok(()) => println!("No panic"),
Err(_) => println!("Caught a panic!"),
}
println!("Program continues...");
// Use cases for catch_unwind:
// - FFI boundaries (don't unwind into C)
// - Thread pools (don't crash the entire pool)
// - Plugin/WASM sandboxing
}