]>
Commit | Line | Data |
---|---|---|
9fa01778 XL |
1 | # Panicking |
2 | ||
3 | Panicking is a core part of the Rust language. Built-in operations like indexing | |
4 | are runtime checked for memory safety. When out of bounds indexing is attempted | |
5 | this results in a panic. | |
6 | ||
7 | In the standard library panicking has a defined behavior: it unwinds the stack | |
8 | of the panicking thread, unless the user opted for aborting the program on | |
9 | panics. | |
10 | ||
532ac7d7 XL |
11 | In programs without standard library, however, the panicking behavior is left |
12 | undefined. A behavior can be chosen by declaring a `#[panic_handler]` function. | |
13 | This function must appear exactly *once* in the dependency graph of a program, | |
14 | and must have the following signature: `fn(&PanicInfo) -> !`, where [`PanicInfo`] | |
15 | is a struct containing information about the location of the panic. | |
9fa01778 XL |
16 | |
17 | [`PanicInfo`]: https://doc.rust-lang.org/core/panic/struct.PanicInfo.html | |
18 | ||
19 | Given that embedded systems range from user facing to safety critical (cannot | |
20 | crash) there's no one size fits all panicking behavior but there are plenty of | |
21 | commonly used behaviors. These common behaviors have been packaged into crates | |
22 | that define the `#[panic_handler]` function. Some examples include: | |
23 | ||
24 | - [`panic-abort`]. A panic causes the abort instruction to be executed. | |
25 | - [`panic-halt`]. A panic causes the program, or the current thread, to halt by | |
26 | entering an infinite loop. | |
27 | - [`panic-itm`]. The panicking message is logged using the ITM, an ARM Cortex-M | |
28 | specific peripheral. | |
29 | - [`panic-semihosting`]. The panicking message is logged to the host using the | |
30 | semihosting technique. | |
31 | ||
32 | [`panic-abort`]: https://crates.io/crates/panic-abort | |
33 | [`panic-halt`]: https://crates.io/crates/panic-halt | |
34 | [`panic-itm`]: https://crates.io/crates/panic-itm | |
35 | [`panic-semihosting`]: https://crates.io/crates/panic-semihosting | |
36 | ||
37 | You may be able to find even more crates searching for the [`panic-handler`] | |
38 | keyword on crates.io. | |
39 | ||
40 | [`panic-handler`]: https://crates.io/keywords/panic-handler | |
41 | ||
42 | A program can pick one of these behaviors simply by linking to the corresponding | |
43 | crate. The fact that the panicking behavior is expressed in the source of | |
44 | an application as a single line of code is not only useful as documentation but | |
45 | can also be used to change the panicking behavior according to the compilation | |
46 | profile. For example: | |
47 | ||
48 | ``` rust,ignore | |
49 | #![no_main] | |
50 | #![no_std] | |
51 | ||
52 | // dev profile: easier to debug panics; can put a breakpoint on `rust_begin_unwind` | |
53 | #[cfg(debug_assertions)] | |
72b1a166 | 54 | use panic_halt as _; |
9fa01778 XL |
55 | |
56 | // release profile: minimize the binary size of the application | |
57 | #[cfg(not(debug_assertions))] | |
72b1a166 | 58 | use panic_abort as _; |
9fa01778 XL |
59 | |
60 | // .. | |
61 | ``` | |
62 | ||
63 | In this example the crate links to the `panic-halt` crate when built with the | |
64 | dev profile (`cargo build`), but links to the `panic-abort` crate when built | |
65 | with the release profile (`cargo build --release`). | |
66 | ||
72b1a166 FG |
67 | > The `use panic_abort as _;` form of the `use` statement is used to ensure the `panic_abort` panic handler is |
68 | > included in our final executable while making it clear to the compiler that we won't explicitly use anything from | |
69 | > the crate. Without the `as _` rename, the compiler would warn that we have an unused import. | |
70 | > Sometimes you might see `extern crate panic_abort` instead, which is an older style used before the | |
71 | > 2018 edition of Rust, and should now only be used for "sysroot" crates (those distributed with Rust itself) such | |
72 | > as `proc_macro`, `alloc`, `std`, and `test`. | |
73 | ||
9fa01778 XL |
74 | ## An example |
75 | ||
76 | Here's an example that tries to index an array beyond its length. The operation | |
77 | results in a panic. | |
78 | ||
532ac7d7 | 79 | ```rust,ignore |
9fa01778 XL |
80 | #![no_main] |
81 | #![no_std] | |
82 | ||
72b1a166 | 83 | use panic_semihosting as _; |
9fa01778 XL |
84 | |
85 | use cortex_m_rt::entry; | |
86 | ||
87 | #[entry] | |
88 | fn main() -> ! { | |
89 | let xs = [0, 1, 2]; | |
90 | let i = xs.len() + 1; | |
91 | let _y = xs[i]; // out of bounds access | |
92 | ||
93 | loop {} | |
94 | } | |
95 | ``` | |
96 | ||
97 | This example chose the `panic-semihosting` behavior which prints the panic | |
98 | message to the host console using semihosting. | |
99 | ||
100 | ``` console | |
101 | $ cargo run | |
102 | Running `qemu-system-arm -cpu cortex-m3 -machine lm3s6965evb (..) | |
103 | panicked at 'index out of bounds: the len is 3 but the index is 4', src/main.rs:12:13 | |
104 | ``` | |
105 | ||
106 | You can try changing the behavior to `panic-halt` and confirm that no message is | |
107 | printed in that case. |