Unsafe Basics
unsafe is a special zone where Rust trusts you to follow the safety rules yourself, since it can't check everything there.In this page:
What unsafe Unlocks
An unsafe block allows a small set of extra operations, such as dereferencing raw pointers or calling unsafe functions, that the compiler cannot fully verify are safe on its own.
Example: What unsafe Unlocks
fn main() {
let value = 10;
let raw_pointer = &value as *const i32;
unsafe {
println!("Value through raw pointer: {}", *raw_pointer);
}
}
Login to try C/C++/Java/PHP code in the editor
Calling an Unsafe Function
Functions marked unsafe fn can only be called from inside an unsafe block, signaling that the caller must uphold certain safety guarantees the function relies on.
Example: Calling an Unsafe Function
unsafe fn dangerous_operation() -> i32 {
42
}
fn main() {
let result = unsafe { dangerous_operation() };
println!("Result: {}", result);
}
Login to try C/C++/Java/PHP code in the editor
Safe Rust Still Applies Around unsafe
Code outside an unsafe block, and even most code inside it, still follows all of Rust's normal type checking and ownership rules -- unsafe only lifts a few specific restrictions.
Example: Safe Rust Still Applies Around unsafe
fn main() {
let mut value = 5;
{
let pointer = &mut value as *mut i32;
unsafe {
*pointer += 10;
}
}
println!("value = {}", value);
}
Login to try C/C++/Java/PHP code in the editor
Wrapping unsafe in a Safe API
A common pattern is to keep unsafe code small and private, exposing only a safe public function that guarantees its preconditions are met before using the unsafe operation internally.
Example: Wrapping unsafe in a Safe API
fn safe_get(arr: &[i32], index: usize) -> Option<i32> {
if index < arr.len() {
Some(unsafe { *arr.get_unchecked(index) })
} else {
None
}
}
fn main() {
let data = [1, 2, 3];
println!("{:?}", safe_get(&data, 1));
println!("{:?}", safe_get(&data, 10));
}
Login to try C/C++/Java/PHP code in the editor
- Reaching for
unsafeto fix an ordinary borrow-checker error, when the real fix is almost always restructuring the safe code. - Assuming
unsafeturns off all of Rust's checks -- it only unlocks a small specific set of extra abilities, like dereferencing raw pointers. - Writing a large
unsafeblock when only one specific line actually needs the extra capability, making it harder to audit.
unsafeblocks unlock a small set of extra abilities not allowed in safe Rust, such as dereferencing raw pointers.- Using
unsafedoes not disable the borrow checker or type checking elsewhere in the code. - Safe abstractions are often built around a small
unsafecore, exposing a fully safe API to callers. unsafeshould be used sparingly and kept as small as possible to make manual review easier.
Chapter Quiz — Complete all 7 topics to unlock
0/7 topics done
Complete these topics first: