id: safety-02 original_id: P.UNS.SAS.02 level: P impact: CRITICAL
Unsafe Code Authors Must Verify Safety Invariants
Summary
When writing unsafe code, you are taking responsibility for upholding all safety invariants that the compiler normally enforces.
Rationale
Unsafe blocks don't disable safety requirements - they transfer responsibility from the compiler to the programmer. You must manually verify what the compiler normally checks.
Safety Invariants to Verify
- Pointer validity: Non-null, aligned, points to valid memory
- Aliasing: No mutable aliasing (two &mut to same memory)
- Initialization: Memory is initialized before read
- Lifetime: References don't outlive their referents
- Type validity: Data matches the expected type's invariants
- Thread safety: Proper synchronization for concurrent access
Bad Example
// DON'T: Blindly trust inputs
unsafe fn process(ptr: *const Data, len: usize) {
for i in 0..len {
// No verification that ptr is valid or len is correct!
let item = &*ptr.add(i);
process_item(item);
}
}
Good Example
// DO: Document and verify invariants
/// Processes a slice of Data items.
///
/// # Safety
///
/// - `ptr` must be non-null and aligned for `Data`
/// - `ptr` must point to `len` consecutive initialized `Data` items
/// - The memory must not be mutated during this call
/// - `len * size_of::<Data>()` must not overflow `isize::MAX`
unsafe fn process(ptr: *const Data, len: usize) {
debug_assert!(!ptr.is_null(), "ptr must not be null");
debug_assert!(ptr.is_aligned(), "ptr must be aligned");
for i in 0..len {
// SAFETY: Caller guarantees ptr points to len valid items
let item = &*ptr.add(i);
process_item(item);
}
}
// DO: Provide safe wrapper when possible
fn process_slice(data: &[Data]) {
// SAFETY: slice guarantees all invariants
unsafe { process(data.as_ptr(), data.len()) }
}
Invariant Documentation Template
/// # Safety
///
/// The caller must ensure that:
/// - [List each invariant]
/// - [Explain why each matters]
Checklist
- Have I listed all safety invariants?
- Can I prove each invariant holds at the call site?
- Have I added debug assertions where possible?
- Have I documented invariants in /// # Safety section?
Related Rules
safety-09: Add SAFETY comment before any unsafe blocksafety-10: Add Safety section in docs for public unsafe functions
你可能感兴趣的文章
Do Not Expose Raw Pointers in Public APIs
Ensure Consistent Data Layout for Custom Types
Add Safety Section in Docs for Public Unsafe Functions
Do Not Use Union Variants Across Different Lifetimes
Use MaybeUninit
Ensure C-ABI Compatibility for Strings Between Rust and C
Do Not Dereference Pointers Cast to Misaligned Types
Use Dedicated Opaque Type Pointers Instead of c_void for C Opaque Types