Prefer pointer::cast Over `as` for Pointer Casting

2026-08-30 浏览 (1)


id: ptr-06 original_id: G.UNS.PTR.03 level: G impact: LOW clippy: ptr_as_ptr

Prefer pointer::cast Over as for Pointer Casting

Summary

Use the cast() method instead of as for pointer type conversions. It's clearer and prevents accidental provenance loss.

Rationale

  • cast() only changes the pointed-to type, not pointer properties
  • as can accidentally convert to integer and back, losing provenance
  • cast() is more explicit about intent
  • Better tooling support (clippy, miri)

Bad Example

// DON'T: Use `as` for pointer casts
fn bad_cast(ptr: *const u8) -> *const i32 {
    ptr as *const i32  // Works, but less clear
}

// DON'T: Accidental provenance loss
fn bad_roundtrip(ptr: *const u8) -> *const u8 {
    let addr = ptr as usize;   // Converts to integer
    addr as *const u8          // Loses provenance information!
}

// DON'T: Multiple `as` casts in chain
fn bad_chain(ptr: *const u8) -> *mut i32 {
    ptr as *mut u8 as *mut i32  // Hard to follow
}

Good Example

// DO: Use cast() for pointer type changes
fn good_cast(ptr: *const u8) -> *const i32 {
    ptr.cast::<i32>()
}

// DO: Use cast_mut() for const-to-mut (when valid)
fn good_cast_mut(ptr: *const u8) -> *mut u8 {
    ptr.cast_mut()  // Only use when mutation is valid!
}

// DO: Use cast_const() for mut-to-const
fn good_cast_const(ptr: *mut u8) -> *const u8 {
    ptr.cast_const()
}

// DO: Chain casts clearly
fn good_chain(ptr: *const u8) -> *mut i32 {
    ptr.cast_mut().cast::<i32>()
}

// DO: Use with_addr() for address manipulation (nightly)
#[cfg(feature = "strict_provenance")]
fn good_provenance(ptr: *const u8, new_addr: usize) -> *const u8 {
    ptr.with_addr(new_addr)  // Preserves provenance
}

Pointer Method Reference

MethodFromToNotes
.cast::<U>()*T*UChanges pointee type
.cast_mut()*const T*mut TRemoves const
.cast_const()*mut T*const TAdds const
.addr()*TusizeGets address (nightly)
.with_addr(usize)*T*TChanges address, keeps provenance
.map_addr(fn)*T*TTransforms address

Provenance Considerations

// Provenance = permission to access memory

// BAD: Loses provenance
let ptr: *const u8 = &data as *const u8;
let addr = ptr as usize;
let ptr2 = addr as *const u8;  // ptr2 has no provenance!

// GOOD: Preserves provenance (nightly strict_provenance)
let ptr2 = ptr.with_addr(addr);  // Still has permission

// GOOD: Use expose/from_exposed when provenance must cross integer
let addr = ptr.expose_addr();  // "Expose" the provenance
let ptr2 = std::ptr::from_exposed_addr(addr);  // Recover it

Checklist

  • Am I using as where cast() would be clearer?
  • Am I accidentally converting through usize?
  • Do I need to preserve provenance?

Related Rules

  • ptr-04: Alignment considerations when casting
  • ptr-05: Don't convert const to mut improperly

你可能感兴趣的文章

Do Not Expose Raw Pointers in Public APIs

Unsafe Code Authors Must Verify Safety Invariants

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

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