Chapter 09¶
Error Handling¶
Rust groups errors into two major categories: recoverable and unrecoverable errors.
Most languages donât distinguish between these two kinds of errors and handle both in the same way, using mechanisms such as exceptions.
Rust doesnât have exceptions. Instead, it has the type Result<T, E> for recoverable errors and the panic! macro that stops execution when the program encounters an unrecoverable error.
Using unwrap_or_else allows us to define some custom, non-panic! error handling.
Unwinding the Stack or Aborting in Response to a Panic¶
By default, when a panic occurs, the program starts unwinding, which means Rust walks back up the stack and cleans up the data from each function it encounters. However, this walking back and cleanup is a lot of work. Rust, therefore, allows you to choose the alternative of immediately aborting, which ends the program without cleaning up.
Using a panic! Backtrace¶
Buffer Overread¶
In C, attempting to read beyond the end of a data structure is undefined behavior. You might get whatever is at the location in memory that would correspond to that element in the data structure, even though the memory doesnât belong to that structure. This is called a buffer overread and can lead to security vulnerabilities if an attacker is able to manipulate the index in such a way as to read data they shouldnât be allowed to that is stored after the data structure.
Propagating Errors (like Throw)¶
When a functionâs implementation calls something that might fail, instead of handling the error within the function itself, you can return the error to the calling code so that it can decide what to do. This is known as propagating the error and gives more control to the calling code, where there might be more information or logic that dictates how the error should be handled than what you have available in the context of your code.
A Shortcut for Propagating Errors: the ? Operator.
use std::fs::File;
use std::io::{self, Read};
fn read_username_from_file() -> Result<String, io::Error> {
let mut username_file = File::open("hello.txt")?;
let mut username = String::new();
username_file.read_to_string(&mut username)?;
Ok(username)
}
A function that returns errors to the calling code using the ? operator