1.8 KiB
1.8 KiB
id, original_id, level, impact
| id | original_id | level | impact |
|---|---|---|---|
| general-01 | P.UNS.01 | P | CRITICAL |
Do Not Abuse Unsafe to Escape Compiler Safety Checks
Summary
Unsafe Rust should not be used as an escape hatch from the borrow checker or other compiler safety mechanisms.
Rationale
The borrow checker exists to prevent memory safety bugs. Using unsafe to bypass it defeats Rust's safety guarantees and introduces potential undefined behavior.
Bad Example
// DON'T: Using unsafe to bypass borrow checker
fn bad_alias() {
let mut data = vec![1, 2, 3];
let ptr = data.as_mut_ptr();
// Unsafe used to create aliasing mutable references
unsafe {
let ref1 = &mut *ptr;
let ref2 = &mut *ptr; // UB: Two mutable references!
*ref1 = 10;
*ref2 = 20;
}
}
Good Example
// DO: Work with the borrow checker, not against it
fn good_sequential() {
let mut data = vec![1, 2, 3];
data[0] = 10;
data[0] = 20; // Sequential mutations are fine
}
// DO: Use interior mutability when needed
use std::cell::RefCell;
fn good_interior_mut() {
let data = RefCell::new(vec![1, 2, 3]);
data.borrow_mut()[0] = 10;
}
Legitimate Uses of Unsafe
- FFI: Calling C functions or implementing C-compatible interfaces
- Low-level abstractions: Implementing collections, synchronization primitives
- Performance: Only after profiling shows measurable improvement, and with careful safety analysis
Checklist
- Have I tried all safe alternatives first?
- Is the borrow checker preventing a genuine design need?
- Can I restructure the code to satisfy the borrow checker?
- If unsafe is necessary, have I documented the safety invariants?
Related Rules
general-02: Don't blindly use unsafe for performancesafety-02: Unsafe code authors must verify safety invariants