]>
Commit | Line | Data |
---|---|---|
c1a9b12d SL |
1 | % Unwinding |
2 | ||
3 | Rust has a *tiered* error-handling scheme: | |
4 | ||
5 | * If something might reasonably be absent, Option is used. | |
6 | * If something goes wrong and can reasonably be handled, Result is used. | |
7 | * If something goes wrong and cannot reasonably be handled, the thread panics. | |
8 | * If something catastrophic happens, the program aborts. | |
9 | ||
10 | Option and Result are overwhelmingly preferred in most situations, especially | |
11 | since they can be promoted into a panic or abort at the API user's discretion. | |
12 | Panics cause the thread to halt normal execution and unwind its stack, calling | |
13 | destructors as if every function instantly returned. | |
14 | ||
15 | As of 1.0, Rust is of two minds when it comes to panics. In the long-long-ago, | |
16 | Rust was much more like Erlang. Like Erlang, Rust had lightweight tasks, | |
17 | and tasks were intended to kill themselves with a panic when they reached an | |
18 | untenable state. Unlike an exception in Java or C++, a panic could not be | |
19 | caught at any time. Panics could only be caught by the owner of the task, at which | |
20 | point they had to be handled or *that* task would itself panic. | |
21 | ||
22 | Unwinding was important to this story because if a task's | |
23 | destructors weren't called, it would cause memory and other system resources to | |
24 | leak. Since tasks were expected to die during normal execution, this would make | |
25 | Rust very poor for long-running systems! | |
26 | ||
27 | As the Rust we know today came to be, this style of programming grew out of | |
28 | fashion in the push for less-and-less abstraction. Light-weight tasks were | |
29 | killed in the name of heavy-weight OS threads. Still, on stable Rust as of 1.0 | |
30 | panics can only be caught by the parent thread. This means catching a panic | |
31 | requires spinning up an entire OS thread! This unfortunately stands in conflict | |
32 | to Rust's philosophy of zero-cost abstractions. | |
33 | ||
34 | There is an unstable API called `catch_panic` that enables catching a panic | |
35 | without spawning a thread. Still, we would encourage you to only do this | |
36 | sparingly. In particular, Rust's current unwinding implementation is heavily | |
37 | optimized for the "doesn't unwind" case. If a program doesn't unwind, there | |
38 | should be no runtime cost for the program being *ready* to unwind. As a | |
39 | consequence, actually unwinding will be more expensive than in e.g. Java. | |
40 | Don't build your programs to unwind under normal circumstances. Ideally, you | |
41 | should only panic for programming errors or *extreme* problems. | |
42 | ||
43 | Rust's unwinding strategy is not specified to be fundamentally compatible | |
44 | with any other language's unwinding. As such, unwinding into Rust from another | |
b039eaaf | 45 | language, or unwinding into another language from Rust is Undefined Behavior. |
c1a9b12d SL |
46 | You must *absolutely* catch any panics at the FFI boundary! What you do at that |
47 | point is up to you, but *something* must be done. If you fail to do this, | |
48 | at best, your application will crash and burn. At worst, your application *won't* | |
49 | crash and burn, and will proceed with completely clobbered state. |