Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 17 additions & 14 deletions src/pointer/invariant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
///
Expand Down Expand Up @@ -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 {}

Expand Down
4 changes: 2 additions & 2 deletions src/pointer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
33 changes: 19 additions & 14 deletions src/pointer/ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -676,8 +676,8 @@ mod _transitions {
#[doc(hidden)]
#[must_use]
#[inline]
pub const fn forget_aligned(self) -> Ptr<'a, T, I::WithAlignment<Any>> {
// SAFETY: `Any` is less restrictive than `Aligned`.
pub const fn forget_aligned(self) -> Ptr<'a, T, I::WithAlignment<Unknown>> {
// SAFETY: `Unknown` is less restrictive than `Aligned`.
unsafe { self.assume_invariants() }
}
}
Expand Down Expand Up @@ -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<U: 'a + ?Sized, F: FnOnce(*mut T) -> *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
Expand Down Expand Up @@ -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) }
}

Expand All @@ -784,7 +785,10 @@ mod _casts {
/// - `u` has the same provenance as `p`
#[doc(hidden)]
#[inline]
pub unsafe fn cast_unsized<U, F, R, S>(self, cast: F) -> Ptr<'a, U, (I::Aliasing, Any, Any)>
pub unsafe fn cast_unsized<U, F, R, S>(
self,
cast: F,
) -> Ptr<'a, U, (I::Aliasing, Unknown, Unknown)>
where
T: Read<I::Aliasing, R>,
U: 'a + ?Sized + Read<I::Aliasing, S>,
Expand Down Expand Up @@ -927,10 +931,11 @@ mod _casts {
// 0. Since `U: Read<I::Aliasing, _>`, 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`.
Expand Down Expand Up @@ -1070,7 +1075,7 @@ mod _project {
pub unsafe fn project<U: 'a + ?Sized>(
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.
Expand Down
2 changes: 1 addition & 1 deletion src/util/macro_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,7 @@ pub unsafe fn transmute_mut<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>(
fn try_cast_or_pme<Src, Dst, I, R>(
src: Ptr<'_, Src, I>,
) -> Result<
Ptr<'_, Dst, (I::Aliasing, invariant::Any, invariant::Valid)>,
Ptr<'_, Dst, (I::Aliasing, invariant::Unknown, invariant::Valid)>,
ValidityError<Ptr<'_, Src, I>, Dst>,
>
where
Expand Down
4 changes: 2 additions & 2 deletions src/util/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,11 @@ impl<I: invariant::Validity> ValidityVariance<I> for Covariant {
pub enum Invariant {}

impl<I: invariant::Alignment> AlignmentVariance<I> for Invariant {
type Applied = invariant::Any;
type Applied = invariant::Unknown;
}

impl<I: invariant::Validity> ValidityVariance<I> for Invariant {
type Applied = invariant::Any;
type Applied = invariant::Unknown;
}

// SAFETY:
Expand Down