|
1 | 1 | # Unrecoverable errors with panic!
|
2 | 2 |
|
3 |
| -You've already seen the way to signal an unrecoverable error: the `panic!` |
4 |
| -macro. Here's an example of using `panic!`: |
| 3 | +Sometimes, bad things happen, and there's nothing that you can do about it. For |
| 4 | +these cases, Rust has a macro, `panic!`. When this macro executes, your program |
| 5 | +will terminate execution, printing a failure message and then quitting. Try |
| 6 | +this program: |
5 | 7 |
|
6 |
| -```rust |
7 |
| -fn check_guess(number: u32) -> bool { |
8 |
| - if number > 100 { |
9 |
| - panic!("Guess was too big: {}", number); |
10 |
| - } |
11 |
| - |
12 |
| - number == 34 |
| 8 | +```rust,should_panic |
| 9 | +fn main() { |
| 10 | + panic!("crash and burn"); |
13 | 11 | }
|
14 | 12 | ```
|
15 | 13 |
|
16 |
| -This function accepts a guess between zero and a hundred, and checks if it's |
17 |
| -equivalent to the correct number, which is `34` in this case. It's kind of a |
18 |
| -silly function, but it's similar to a real example you've already seen: |
19 |
| -indexing vectors: |
| 14 | +If you run it, you'll see something like this: |
| 15 | + |
| 16 | +```bash |
| 17 | +$ cargo run |
| 18 | + Compiling panic v0.1.0 (file:///home/steve/tmp/panic) |
| 19 | + Finished debug [unoptimized + debuginfo] target(s) in 0.25 secs |
| 20 | + Running `target/debug/panic` |
| 21 | +thread 'main' panicked at 'crash and burn', src/main.rs:2 |
| 22 | +note: Run with `RUST_BACKTRACE=1` for a backtrace. |
| 23 | +error: Process didn't exit successfully: `target/debug/panic` (exit code: 101) |
| 24 | +``` |
| 25 | +
|
| 26 | +There are three lines of error message here. The first line shows our panic |
| 27 | +message and the place in our source code where the panic occurred: |
| 28 | +`src/main.rs`, line two. |
| 29 | +
|
| 30 | +But that only shows us the exact line that called `panic!`. That's not always |
| 31 | +useful. Let's modify our example slightly: |
20 | 32 |
|
21 | 33 | ```rust,should_panic
|
22 |
| -let v = vec![1, 2, 3]; |
| 34 | +fn main() { |
| 35 | + let v = vec![1, 2, 3]; |
| 36 | +
|
| 37 | + v[100]; |
| 38 | +} |
| 39 | +``` |
| 40 | +
|
| 41 | +We attempt to access the hundredth element of our vector, but it only has three |
| 42 | +elements. In this situation, Rust will panic. Let's try it: |
| 43 | + |
| 44 | +```bash |
| 45 | +$ cargo run |
| 46 | + Compiling panic v0.1.0 (file:///home/steve/tmp/panic) |
| 47 | + Finished debug [unoptimized + debuginfo] target(s) in 0.27 secs |
| 48 | + Running `target/debug/panic` |
| 49 | +thread 'main' panicked at 'index out of bounds: the len is 3 but the index is |
| 50 | +100', ../src/libcollections/vec.rs:1265 |
| 51 | +note: Run with `RUST_BACKTRACE=1` for a backtrace. |
| 52 | +error: Process didn't exit successfully: `target/debug/panic` (exit code: 101) |
| 53 | +``` |
23 | 54 |
|
24 |
| -v[1000]; // this will panic |
| 55 | +This points at a file we didn't write, `../src/libcollections/vec.rs`, line 1265. |
| 56 | +That's the implementation of `Vec<T>` in the standard library. While it's easy |
| 57 | +to see in this short program where the error was, it would be nicer if we could |
| 58 | +have Rust tell us what line in our program caused the error. |
| 59 | +
|
| 60 | +That's what the next line, the `note` is about. If we set the `RUST_BACKTRACE` |
| 61 | +environment variable, we'll get a backtrace of exactly how the error happend. |
| 62 | +Let's try it: |
| 63 | +
|
| 64 | +```bash |
| 65 | +$ RUST_BACKTRACE=1 cargo run |
| 66 | + Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs |
| 67 | + Running `target/debug/panic` |
| 68 | +thread 'main' panicked at 'index out of bounds: the len is 3 but the index is |
| 69 | +100', ../src/libcollections/vec.rs:1265 |
| 70 | +stack backtrace: |
| 71 | + 1: 0x560956150ae9 - |
| 72 | +std::sys::backtrace::tracing::imp::write::h482d45d91246faa2 |
| 73 | + 2: 0x56095615345c - |
| 74 | +std::panicking::default_hook::_{{closure}}::h89158f66286b674e |
| 75 | + 3: 0x56095615291e - std::panicking::default_hook::h9e30d428ee3b0c43 |
| 76 | + 4: 0x560956152f88 - |
| 77 | +std::panicking::rust_panic_with_hook::h2224f33fb7bf2f4c |
| 78 | + 5: 0x560956152e22 - std::panicking::begin_panic::hcb11a4dc6d779ae5 |
| 79 | + 6: 0x560956152d50 - std::panicking::begin_panic_fmt::h310416c62f3935b3 |
| 80 | + 7: 0x560956152cd1 - rust_begin_unwind |
| 81 | + 8: 0x560956188a2f - core::panicking::panic_fmt::hc5789f4e80194729 |
| 82 | + 9: 0x5609561889d3 - |
| 83 | +core::panicking::panic_bounds_check::hb2d969c3cc11ed08 |
| 84 | + 10: 0x56095614c075 - _<collections..vec..Vec<T> as |
| 85 | +core..ops..Index<usize>>::index::hb9f10d3dadbe8101 |
| 86 | + at ../src/libcollections/vec.rs:1265 |
| 87 | + 11: 0x56095614c134 - panic::main::h2d7d3751fb8705e2 |
| 88 | + at /home/steve/tmp/panic/src/main.rs:4 |
| 89 | + 12: 0x56095615af46 - __rust_maybe_catch_panic |
| 90 | + 13: 0x560956152082 - std::rt::lang_start::h352a66f5026f54bd |
| 91 | + 14: 0x56095614c1b3 - main |
| 92 | + 15: 0x7f75b88ed72f - __libc_start_main |
| 93 | + 16: 0x56095614b3c8 - _start |
| 94 | + 17: 0x0 - <unknown> |
| 95 | +error: Process didn't exit successfully: `target/debug/panic` (exit code: 101) |
25 | 96 | ```
|
26 | 97 |
|
27 |
| -The implementation of indexing with `[]` looks similar to our `check_guess` |
28 |
| -function above: check if the number is larger than the length of the vector, |
29 |
| -and if it is, panic. |
| 98 | +That's a lot of output! Line `11` there has the line in our project: |
| 99 | +`src/main.rs` line four. We've been looking at the error message, but Cargo |
| 100 | +also told us something important about backtraces early on: `[unoptimized + |
| 101 | +debuginfo]`. 'debuginfo' is what enables the file names to be shown here. |
| 102 | +If we instead compile with `--release`: |
| 103 | +
|
| 104 | +```bash |
| 105 | +$ RUST_BACKTRACE=1 cargo run --release |
| 106 | + Compiling panic v0.1.0 (file:///home/steve/tmp/panic) |
| 107 | + Finished release [optimized] target(s) in 0.28 secs |
| 108 | + Running `target/release/panic` |
| 109 | +thread 'main' panicked at 'index out of bounds: the len is 3 but the index is |
| 110 | +100', ../src/libcollections/vec.rs:1265 |
| 111 | +stack backtrace: |
| 112 | + 1: 0x565238fd0e79 - |
| 113 | +std::sys::backtrace::tracing::imp::write::h482d45d91246faa2 |
| 114 | + 2: 0x565238fd37ec - |
| 115 | +std::panicking::default_hook::_{{closure}}::h89158f66286b674e |
| 116 | + 3: 0x565238fd2cae - std::panicking::default_hook::h9e30d428ee3b0c43 |
| 117 | + 4: 0x565238fd3318 - |
| 118 | +std::panicking::rust_panic_with_hook::h2224f33fb7bf2f4c |
| 119 | + 5: 0x565238fd31b2 - std::panicking::begin_panic::hcb11a4dc6d779ae5 |
| 120 | + 6: 0x565238fd30e0 - std::panicking::begin_panic_fmt::h310416c62f3935b3 |
| 121 | + 7: 0x565238fd3061 - rust_begin_unwind |
| 122 | + 8: 0x565239008dbf - core::panicking::panic_fmt::hc5789f4e80194729 |
| 123 | + 9: 0x565239008d63 - |
| 124 | +core::panicking::panic_bounds_check::hb2d969c3cc11ed08 |
| 125 | + 10: 0x565238fcc526 - panic::main::h2d7d3751fb8705e2 |
| 126 | + 11: 0x565238fdb2d6 - __rust_maybe_catch_panic |
| 127 | + 12: 0x565238fd2412 - std::rt::lang_start::h352a66f5026f54bd |
| 128 | + 13: 0x7f36aad6372f - __libc_start_main |
| 129 | + 14: 0x565238fcc408 - _start |
| 130 | + 15: 0x0 - <unknown> |
| 131 | +error: Process didn't exit successfully: `target/release/panic` (exit code: |
| 132 | +101) |
| 133 | +``` |
30 | 134 |
|
31 |
| -Why do we need to panic? There's no number type for "between zero and a |
32 |
| -hundred" in Rust, so we are accepting a `u32`, and then checking in the |
33 |
| -function's body to make sure the guess is in-bounds. If the number is too big, |
34 |
| -there's been an error: someone made a mistake. We then invoke `panic!` to say |
35 |
| -"something went wrong, we cannot continue to run this program." |
| 135 | +Now it just says 'optimized', and we don't have the file names any more. These |
| 136 | +settings are only the default; you can include debuginfo in a release build, |
| 137 | +or exclude it from a debug build, by configuring Cargo. See its documentation |
| 138 | +for more details: http://doc.crates.io/manifest.html#the-profile-sections |
36 | 139 |
|
| 140 | +So why does Rust panic here? In this case, using `[]` is supposed to return |
| 141 | +a number. But if you pass it an invalid index, there's no number Rust could |
| 142 | +return here, it would be wrong. So the only thing that we can do is terminate |
| 143 | +the program. |
0 commit comments