Unsafe Code Authors Must Verify Safety Invariants

2026-08-30 浏览 (2)


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

  1. Pointer validity: Non-null, aligned, points to valid memory
  2. Aliasing: No mutable aliasing (two &mut to same memory)
  3. Initialization: Memory is initialized before read
  4. Lifetime: References don't outlive their referents
  5. Type validity: Data matches the expected type's invariants
  6. 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 block
  • safety-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 for Uninitialized Memory

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

Choose Appropriate Data Layout for Struct/Tuple/Enum

Handle Errors Properly in FFI

  • 所属分类: AI
  • 本文标签: rust
  • 版权声明: 本文链接 https://seaxiang.com/blog/MF6LCYyA