diff --git a/src/pointer/invariant.rs b/src/pointer/invariant.rs index c48e0a196c..4d963398c7 100644 --- a/src/pointer/invariant.rs +++ b/src/pointer/invariant.rs @@ -81,24 +81,26 @@ pub trait Validity: Sealed {} /// Exclusive`. pub trait Reference: Aliasing + Sealed {} -/// No requirement - any invariant is allowed. -pub enum Any {} -impl Aliasing for Any { +/// It is unknown whether any invariant holds. +pub enum Unknown {} + +impl Alignment for Unknown {} +impl Validity for Unknown {} + +/// The `Ptr<'a, T>` does not permit any reads or writes from or to its referent. +pub enum Inaccessible {} + +impl Aliasing for Inaccessible { const IS_EXCLUSIVE: bool = false; - // SAFETY: Since we don't know what aliasing model this is, we have to be - // conservative. Invariance is strictly more restrictive than any other - // variance model, so this can never cause soundness issues. - // - // `fn() -> T` and `fn(T) -> ()` are covariant and contravariant in `T`, - // respectively. [1] Thus, `fn(T) -> T` is invariant in `T`. Thus, `fn(&'a - // T) -> &'a T` is invariant in `'a` and `T`. + // SAFETY: Inaccessible `Ptr`s permit neither reads nor writes, and so it + // doesn't matter how long the referent actually lives. Thus, covariance is + // fine (and is chosen because it is maximally permissive). Shared + // references are covariant [1]. // // [1] https://doc.rust-lang.org/1.81.0/reference/subtyping.html#variance - type Variance<'a, T: 'a + ?Sized> = fn(&'a T) -> &'a T; + type Variance<'a, T: 'a + ?Sized> = &'a T; } -impl Alignment for Any {} -impl Validity for Any {} /// The `Ptr<'a, T>` adheres to the aliasing rules of a `&'a T`. /// @@ -212,8 +214,9 @@ mod sealed { pub trait Sealed {} - impl Sealed for Any {} + impl Sealed for Unknown {} + impl Sealed for Inaccessible {} impl Sealed for Shared {} impl Sealed for Exclusive {} diff --git a/src/pointer/mod.rs b/src/pointer/mod.rs index ceda0c6bd0..e7b8c0e802 100644 --- a/src/pointer/mod.rs +++ b/src/pointer/mod.rs @@ -24,14 +24,14 @@ use crate::Unaligned; /// to [`TryFromBytes::is_bit_valid`]. /// /// [`TryFromBytes::is_bit_valid`]: crate::TryFromBytes::is_bit_valid -pub type Maybe<'a, T, Aliasing = invariant::Shared, Alignment = invariant::Any> = +pub type Maybe<'a, T, Aliasing = invariant::Shared, Alignment = invariant::Unknown> = Ptr<'a, T, (Aliasing, Alignment, invariant::Initialized)>; /// A semi-user-facing wrapper type representing a maybe-aligned reference, for /// use in [`TryFromBytes::is_bit_valid`]. /// /// [`TryFromBytes::is_bit_valid`]: crate::TryFromBytes::is_bit_valid -pub type MaybeAligned<'a, T, Aliasing = invariant::Shared, Alignment = invariant::Any> = +pub type MaybeAligned<'a, T, Aliasing = invariant::Shared, Alignment = invariant::Unknown> = Ptr<'a, T, (Aliasing, Alignment, invariant::Valid)>; // These methods are defined on the type alias, `MaybeAligned`, so as to bring diff --git a/src/pointer/ptr.rs b/src/pointer/ptr.rs index 78bf23d1b3..b8ecc4afb0 100644 --- a/src/pointer/ptr.rs +++ b/src/pointer/ptr.rs @@ -676,8 +676,8 @@ mod _transitions { #[doc(hidden)] #[must_use] #[inline] - pub const fn forget_aligned(self) -> Ptr<'a, T, I::WithAlignment> { - // SAFETY: `Any` is less restrictive than `Aligned`. + pub const fn forget_aligned(self) -> Ptr<'a, T, I::WithAlignment> { + // SAFETY: `Unknown` is less restrictive than `Aligned`. unsafe { self.assume_invariants() } } } @@ -706,15 +706,14 @@ mod _casts { /// following properties: /// - `u` addresses a subset of the bytes addressed by `p` /// - `u` has the same provenance as `p` - /// - If `I::Aliasing` is [`Any`] or [`Shared`], `UnsafeCell`s in `*u` - /// must exist at ranges identical to those at which `UnsafeCell`s - /// exist in `*p` + /// - If `I::Aliasing` is [`Shared`], `UnsafeCell`s in `*u` must exist + /// at ranges identical to those at which `UnsafeCell`s exist in `*p` #[doc(hidden)] #[inline] pub unsafe fn cast_unsized_unchecked *mut U>( self, cast: F, - ) -> Ptr<'a, U, (I::Aliasing, Any, Any)> { + ) -> Ptr<'a, U, (I::Aliasing, Unknown, Unknown)> { let ptr = cast(self.as_inner().as_non_null().as_ptr()); // SAFETY: Caller promises that `cast` returns a pointer whose @@ -768,9 +767,11 @@ mod _casts { // pointer will permit mutation of this byte during `'a`, by // invariant on `self`, no other code assumes that this will // not happen. + // - `Inaccessible`: There are no restrictions we need to uphold. // 7. `ptr`, trivially, conforms to the alignment invariant of - // `Any`. - // 8. `ptr`, trivially, conforms to the validity invariant of `Any`. + // `Unknown`. + // 8. `ptr`, trivially, conforms to the validity invariant of + // `Unknown`. unsafe { Ptr::new(ptr) } } @@ -784,7 +785,10 @@ mod _casts { /// - `u` has the same provenance as `p` #[doc(hidden)] #[inline] - pub unsafe fn cast_unsized(self, cast: F) -> Ptr<'a, U, (I::Aliasing, Any, Any)> + pub unsafe fn cast_unsized( + self, + cast: F, + ) -> Ptr<'a, U, (I::Aliasing, Unknown, Unknown)> where T: Read, U: 'a + ?Sized + Read, @@ -927,10 +931,11 @@ mod _casts { // 0. Since `U: Read`, either: // - `I::Aliasing` is `Exclusive`, in which case both `src` and // `ptr` conform to `Exclusive` - // - `I::Aliasing` is `Shared` or `Any` and `U` is `Immutable` - // (we already know that `[u8]: Immutable`). In this case, - // neither `U` nor `[u8]` permit mutation, and so `Shared` - // aliasing is satisfied. + // - `I::Aliasing` is `Shared` or `Inaccessible` and `U` is + // `Immutable` (we already know that `[u8]: Immutable`). In + // this case, neither `U` nor `[u8]` permit mutation, and so + // `Shared` aliasing is satisfied. `Inaccessible` is trivially + // satisfied since it imposes no requirements. // 1. `ptr` conforms to the alignment invariant of `Aligned` because // it is derived from `try_cast_into`, which promises that the // object described by `target` is validly aligned for `U`. @@ -1070,7 +1075,7 @@ mod _project { pub unsafe fn project( self, projector: impl FnOnce(*mut T) -> *mut U, - ) -> Ptr<'a, U, (I::Aliasing, Any, Initialized)> { + ) -> Ptr<'a, U, (I::Aliasing, Unknown, Initialized)> { // TODO(#1122): If `cast_unsized` were able to reason that, when // casting from an `Initialized` pointer, the result is another // `Initialized` pointer, we could remove this method entirely. diff --git a/src/util/macro_util.rs b/src/util/macro_util.rs index 1064a5b76b..7a904438ee 100644 --- a/src/util/macro_util.rs +++ b/src/util/macro_util.rs @@ -520,7 +520,7 @@ pub unsafe fn transmute_mut<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>( fn try_cast_or_pme( src: Ptr<'_, Src, I>, ) -> Result< - Ptr<'_, Dst, (I::Aliasing, invariant::Any, invariant::Valid)>, + Ptr<'_, Dst, (I::Aliasing, invariant::Unknown, invariant::Valid)>, ValidityError, Dst>, > where diff --git a/src/util/mod.rs b/src/util/mod.rs index b00437cd7c..dd2e5bdd61 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -99,11 +99,11 @@ impl ValidityVariance for Covariant { pub enum Invariant {} impl AlignmentVariance for Invariant { - type Applied = invariant::Any; + type Applied = invariant::Unknown; } impl ValidityVariance for Invariant { - type Applied = invariant::Any; + type Applied = invariant::Unknown; } // SAFETY: