Unsafe code and external boundaries
Unsafe code and external boundaries
Rust’s safe interfaces let beginners work without manually proving pointer validity. Some low-level operations and foreign interfaces need unsafe code. Unsafe marks a boundary where the programmer must uphold specific requirements the compiler cannot fully check; it is not a performance switch or permission to ignore every rule.
What you’ll learn
- Identify the validity requirements for a raw-pointer read.
- Explain why unsafe does not repair an invalid pointer.
Unsafe code and external boundaries in action
Live score owns valid storage
The raw pointer refers to the live integer score.
Live score owns valid storageRaw pointer refers to it
The unsafe dereference reads 80, and printing displays it.
Raw pointer refers to itJustified read observes 80
The block does not change the integer’s lifetime or prevent a dangling pointer in a different program.
Justified read observes 80
Unsafe code and external boundaries explained
Dereferencing a raw pointer requires an unsafe block. The pointer below is created from a valid reference, remains within the owner’s lifetime and is only read while no conflicting mutable access occurs. Those facts justify this narrowly scoped operation. Ordinary reference-based code is preferable when it can express the same task.
Work through the Rust program
Save the complete source as main.rs in the Rust environment. No standard input is needed.
Rust 2024 · complete program
fn main() {
let score = 80;
let pointer: *const i32 = &score;
// SAFETY: score is alive, initialized, aligned, and not being mutated.
let observed = unsafe { *pointer };
println!("Observed: {observed}");
}Expected output
Observed: 80Follow the execution
The raw pointer refers to the live integer score. The unsafe dereference reads 80, and printing displays it. The block does not change the integer’s lifetime or prevent a dangling pointer in a different program.
Try the complete program in the Rust compiler. For tests, Cargo commands and local files, use the specified local environment.
Try a small variation
Your task: Would adding unsafe make a pointer to already freed storage valid?
Rust 2024 · complete program
fn main() {
let score = 80;
let pointer: *const i32 = &score;
// SAFETY: score is alive, initialized, aligned, and not being mutated.
let observed = unsafe { *pointer };
println!("Observed: {observed}");
}Worked answer
No. Unsafe transfers responsibility for upholding the operation’s requirements to the programmer. Violating them can cause undefined behavior.
Mistakes and limits to recognize
Foreign function interfaces must agree on ABI, representation, lifetimes and ownership contracts. Rust 2024 has explicit requirements for unsafe external declarations and certain attributes. This lesson introduces the boundary; it is not a license to build a safe foreign API without checking its documentation.
Check your understanding
Take the idea into your next program
No. Unsafe transfers responsibility for upholding the operation’s requirements to the programmer. Violating them can cause undefined behavior. Foreign function interfaces must agree on ABI, representation, lifetimes and ownership contracts.
Further reading: the official Rust Book on unsafe code and external boundaries.
Reaching the recap and completing the quizzes are separate milestones.