]> git.proxmox.com Git - rustc.git/blame - src/doc/book/src/ch09-01-unrecoverable-errors-with-panic.md
New upstream version 1.78.0+dfsg1
[rustc.git] / src / doc / book / src / ch09-01-unrecoverable-errors-with-panic.md
CommitLineData
13cf67c4
XL
1## Unrecoverable Errors with `panic!`
2
3Sometimes, bad things happen in your code, and there’s nothing you can do about
923072b8
FG
4it. In these cases, Rust has the `panic!` macro. There are two ways to cause a
5panic in practice: by taking an action that causes our code to panic (such as
6accessing an array past the end) or by explicitly calling the `panic!` macro.
7In both cases, we cause a panic in our program. By default, these panics will
8print a failure message, unwind, clean up the stack, and quit. Via an
9environment variable, you can also have Rust display the call stack when a
10panic occurs to make it easier to track down the source of the panic.
13cf67c4
XL
11
12> ### Unwinding the Stack or Aborting in Response to a Panic
13>
14> By default, when a panic occurs, the program starts *unwinding*, which
15> means Rust walks back up the stack and cleans up the data from each function
5099ac24
FG
16> it encounters. However, this walking back and cleanup is a lot of work. Rust,
17> therefore, allows you to choose the alternative of immediately *aborting*,
923072b8
FG
18> which ends the program without cleaning up.
19>
20> Memory that the program was using will then need to be cleaned
21> up by the operating system. If in your project you need to make the resulting
22> binary as small as possible, you can switch from unwinding to aborting upon a
23> panic by adding `panic = 'abort'` to the appropriate `[profile]` sections in
24> your *Cargo.toml* file. For example, if you want to abort on panic in release
25> mode, add this:
13cf67c4
XL
26>
27> ```toml
28> [profile.release]
29> panic = 'abort'
30> ```
31
32Let’s try calling `panic!` in a simple program:
33
34<span class="filename">Filename: src/main.rs</span>
35
36```rust,should_panic,panics
74b04a01 37{{#rustdoc_include ../listings/ch09-error-handling/no-listing-01-panic/src/main.rs}}
13cf67c4
XL
38```
39
40When you run the program, you’ll see something like this:
41
f035d41b 42```console
74b04a01 43{{#include ../listings/ch09-error-handling/no-listing-01-panic/output.txt}}
13cf67c4
XL
44```
45
69743fb6
XL
46The call to `panic!` causes the error message contained in the last two lines.
47The first line shows our panic message and the place in our source code where
9fa01778
XL
48the panic occurred: *src/main.rs:2:5* indicates that it’s the second line,
49fifth character of our *src/main.rs* file.
13cf67c4
XL
50
51In this case, the line indicated is part of our code, and if we go to that
52line, we see the `panic!` macro call. In other cases, the `panic!` call might
53be in code that our code calls, and the filename and line number reported by
54the error message will be someone else’s code where the `panic!` macro is
55called, not the line of our code that eventually led to the `panic!` call. We
56can use the backtrace of the functions the `panic!` call came from to figure
5099ac24
FG
57out the part of our code that is causing the problem. We’ll discuss backtraces
58in more detail next.
13cf67c4
XL
59
60### Using a `panic!` Backtrace
61
62Let’s look at another example to see what it’s like when a `panic!` call comes
63from a library because of a bug in our code instead of from our code calling
64the macro directly. Listing 9-1 has some code that attempts to access an
5099ac24 65index in a vector beyond the range of valid indexes.
13cf67c4
XL
66
67<span class="filename">Filename: src/main.rs</span>
68
69```rust,should_panic,panics
74b04a01 70{{#rustdoc_include ../listings/ch09-error-handling/listing-09-01/src/main.rs}}
13cf67c4
XL
71```
72
73<span class="caption">Listing 9-1: Attempting to access an element beyond the
69743fb6 74end of a vector, which will cause a call to `panic!`</span>
13cf67c4 75
69743fb6 76Here, we’re attempting to access the 100th element of our vector (which is at
5099ac24
FG
77index 99 because indexing starts at zero), but the vector has only 3 elements.
78In this situation, Rust will panic. Using `[]` is supposed to return an
79element, but if you pass an invalid index, there’s no element that Rust could
80return here that would be correct.
13cf67c4 81
74b04a01
XL
82In C, attempting to read beyond the end of a data structure is undefined
83behavior. You might get whatever is at the location in memory that would
84correspond to that element in the data structure, even though the memory
85doesn’t belong to that structure. This is called a *buffer overread* and can
86lead to security vulnerabilities if an attacker is able to manipulate the index
87in such a way as to read data they shouldn’t be allowed to that is stored after
88the data structure.
13cf67c4
XL
89
90To protect your program from this sort of vulnerability, if you try to read an
91element at an index that doesn’t exist, Rust will stop execution and refuse to
92continue. Let’s try it and see:
93
f035d41b 94```console
74b04a01 95{{#include ../listings/ch09-error-handling/listing-09-01/output.txt}}
13cf67c4
XL
96```
97
6a06907d
XL
98This error points at line 4 of our `main.rs` where we attempt to access index
9999. The next note line tells us that we can set the `RUST_BACKTRACE`
100environment variable to get a backtrace of exactly what happened to cause the
101error. A *backtrace* is a list of all the functions that have been called to
102get to this point. Backtraces in Rust work as they do in other languages: the
103key to reading the backtrace is to start from the top and read until you see
104files you wrote. That’s the spot where the problem originated. The lines above
5099ac24
FG
105that spot are code that your code has called; the lines below are code that
106called your code. These before-and-after lines might include core Rust code,
6a06907d
XL
107standard library code, or crates that you’re using. Let’s try getting a
108backtrace by setting the `RUST_BACKTRACE` environment variable to any value
109except 0. Listing 9-2 shows output similar to what you’ll see.
13cf67c4 110
74b04a01
XL
111<!-- manual-regeneration
112cd listings/ch09-error-handling/listing-09-01
113RUST_BACKTRACE=1 cargo run
114copy the backtrace output below
115check the backtrace number mentioned in the text below the listing
116-->
117
f035d41b 118```console
13cf67c4 119$ RUST_BACKTRACE=1 cargo run
c620b35d
FG
120thread 'main' panicked at src/main.rs:4:6:
121index out of bounds: the len is 3 but the index is 99
13cf67c4 122stack backtrace:
fc512014 123 0: rust_begin_unwind
c620b35d 124 at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/std/src/panicking.rs:645:5
fc512014 125 1: core::panicking::panic_fmt
c620b35d 126 at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/panicking.rs:72:14
fc512014 127 2: core::panicking::panic_bounds_check
c620b35d 128 at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/panicking.rs:208:5
fc512014 129 3: <usize as core::slice::index::SliceIndex<[T]>>::index
c620b35d 130 at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/slice/index.rs:255:10
fc512014 131 4: core::slice::index::<impl core::ops::index::Index<I> for [T]>::index
c620b35d 132 at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/slice/index.rs:18:9
2b03887a 133 5: <alloc::vec::Vec<T,A> as core::ops::index::Index<I>>::index
c620b35d 134 at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/alloc/src/vec/mod.rs:2770:9
fc512014 135 6: panic::main
c620b35d 136 at ./src/main.rs:4:6
fc512014 137 7: core::ops::function::FnOnce::call_once
c620b35d 138 at /rustc/07dca489ac2d933c78d3c5158e3f43beefeb02ce/library/core/src/ops/function.rs:250:5
fc512014 139note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
13cf67c4
XL
140```
141
142<span class="caption">Listing 9-2: The backtrace generated by a call to
143`panic!` displayed when the environment variable `RUST_BACKTRACE` is set</span>
144
145That’s a lot of output! The exact output you see might be different depending
146on your operating system and Rust version. In order to get backtraces with this
147information, debug symbols must be enabled. Debug symbols are enabled by
148default when using `cargo build` or `cargo run` without the `--release` flag,
149as we have here.
150
5099ac24
FG
151In the output in Listing 9-2, line 6 of the backtrace points to the line in our
152project that’s causing the problem: line 4 of *src/main.rs*. If we don’t want
153our program to panic, we should start our investigation at the location pointed
154to by the first line mentioning a file we wrote. In Listing 9-1, where we
155deliberately wrote code that would panic, the way to fix the panic is to not
156request an element beyond the range of the vector indexes. When your code
157panics in the future, you’ll need to figure out what action the code is taking
158with what values to cause the panic and what the code should do instead.
13cf67c4
XL
159
160We’ll come back to `panic!` and when we should and should not use `panic!` to
dc9dc135
XL
161handle error conditions in the [“To `panic!` or Not to
162`panic!`”][to-panic-or-not-to-panic]<!-- ignore --> section later in this
163chapter. Next, we’ll look at how to recover from an error using `Result`.
9fa01778
XL
164
165[to-panic-or-not-to-panic]:
166ch09-03-to-panic-or-not-to-panic.html#to-panic-or-not-to-panic