Unwinding

Rust has a tiered error-handling scheme:

  • If something might reasonably be absent, Option is used.
  • If something goes wrong and can reasonably be handled, Result is used.
  • If something goes wrong and cannot reasonably be handled, the thread panics.
  • If something catastrophic happens, the program aborts.

Option and Result are overwhelmingly preferred in most situations, especiallysince they can be promoted into a panic or abort at the API user’s discretion.Panics cause the thread to halt normal execution and unwind its stack, callingdestructors as if every function instantly returned.

As of 1.0, Rust is of two minds when it comes to panics. In the long-long-ago,Rust was much more like Erlang. Like Erlang, Rust had lightweight tasks,and tasks were intended to kill themselves with a panic when they reached anuntenable state. Unlike an exception in Java or C++, a panic could not becaught at any time. Panics could only be caught by the owner of the task, at whichpoint they had to be handled or that task would itself panic.

Unwinding was important to this story because if a task’sdestructors weren’t called, it would cause memory and other system resources toleak. Since tasks were expected to die during normal execution, this would makeRust very poor for long-running systems!

As the Rust we know today came to be, this style of programming grew out offashion in the push for less-and-less abstraction. Light-weight tasks werekilled in the name of heavy-weight OS threads. Still, on stable Rust as of 1.0panics can only be caught by the parent thread. This means catching a panicrequires spinning up an entire OS thread! This unfortunately stands in conflictto Rust’s philosophy of zero-cost abstractions.

There is an unstable API called catch_panic that enables catching a panicwithout spawning a thread. Still, we would encourage you to only do thissparingly. In particular, Rust’s current unwinding implementation is heavilyoptimized for the “doesn’t unwind” case. If a program doesn’t unwind, thereshould be no runtime cost for the program being ready to unwind. As aconsequence, actually unwinding will be more expensive than in e.g. Java.Don’t build your programs to unwind under normal circumstances. Ideally, youshould only panic for programming errors or extreme problems.

Rust’s unwinding strategy is not specified to be fundamentally compatiblewith any other language’s unwinding. As such, unwinding into Rust from anotherlanguage, or unwinding into another language from Rust is Undefined Behavior.You must absolutely catch any panics at the FFI boundary! What you do at thatpoint is up to you, but something must be done. If you fail to do this,at best, your application will crash and burn. At worst, your application won’tcrash and burn, and will proceed with completely clobbered state.