Skip to content
Open
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
6 changes: 3 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3920,7 +3920,7 @@ pub unsafe trait FromBytes: FromZeros {
{
static_assert_dst_is_not_zst!(Self);
match Ptr::from_mut(source).try_cast_into_no_leftover::<_, BecauseExclusive>(None) {
Ok(ptr) => Ok(ptr.recall_validity::<_, (_, (_, _))>().as_mut()),
Ok(ptr) => Ok(ptr.recall_validity::<_, BecauseExclusive>().as_mut()),
Err(err) => Err(err.map_src(|src| src.as_mut())),
}
}
Expand Down Expand Up @@ -4390,7 +4390,7 @@ pub unsafe trait FromBytes: FromZeros {
let source = Ptr::from_mut(source);
let maybe_slf = source.try_cast_into_no_leftover::<_, BecauseImmutable>(Some(count));
match maybe_slf {
Ok(slf) => Ok(slf.recall_validity::<_, (_, (_, BecauseExclusive))>().as_mut()),
Ok(slf) => Ok(slf.recall_validity::<_, BecauseExclusive>().as_mut()),
Err(err) => Err(err.map_src(|s| s.as_mut())),
}
}
Expand Down Expand Up @@ -4869,7 +4869,7 @@ fn mut_from_prefix_suffix<T: FromBytes + IntoBytes + KnownLayout + ?Sized>(
let (slf, prefix_suffix) = Ptr::from_mut(source)
.try_cast_into::<_, BecauseExclusive>(cast_type, meta)
.map_err(|err| err.map_src(|s| s.as_mut()))?;
Ok((slf.recall_validity::<_, (_, (_, _))>().as_mut(), prefix_suffix.as_mut()))
Ok((slf.recall_validity::<_, BecauseExclusive>().as_mut(), prefix_suffix.as_mut()))
}

/// Analyzes whether a type is [`IntoBytes`].
Expand Down
6 changes: 3 additions & 3 deletions src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -572,7 +572,7 @@ macro_rules! try_transmute {
$crate::util::macro_util::core_reexport::mem::transmute(e)
})
} else {
$crate::util::macro_util::try_transmute::<_, _>(e)
$crate::util::macro_util::try_transmute(e)
}
}}
}
Expand Down Expand Up @@ -679,7 +679,7 @@ macro_rules! try_transmute_ref {

Ok(&u)
} else {
$crate::util::macro_util::try_transmute_ref::<_, _>(e)
$crate::util::macro_util::try_transmute_ref(e)
}
}}
}
Expand Down Expand Up @@ -788,7 +788,7 @@ macro_rules! try_transmute_mut {

Ok(&mut u)
} else {
$crate::util::macro_util::try_transmute_mut::<_, _>(e)
$crate::util::macro_util::try_transmute_mut(e)
}
}}
}
Expand Down
36 changes: 18 additions & 18 deletions src/pointer/invariant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,24 +198,24 @@ unsafe impl<ST: ?Sized, DT: ?Sized> CastableFrom<ST, Uninit, Uninit> for DT {}
// SAFETY: `SV = DV = Initialized`.
unsafe impl<ST: ?Sized, DT: ?Sized> CastableFrom<ST, Initialized, Initialized> for DT {}

/// [`Ptr`](crate::Ptr) referents that permit unsynchronized read operations.
///
/// `T: Read<A, R>` implies that a pointer to `T` with aliasing `A` permits
/// unsynchronized read operations. This can be because `A` is [`Exclusive`] or
/// because `T` does not permit interior mutation.
///
/// # Safety
///
/// `T: Read<A, R>` if either of the following conditions holds:
/// - `A` is [`Exclusive`]
/// - `T` implements [`Immutable`](crate::Immutable)
///
/// As a consequence, if `T: Read<A, R>`, then any `Ptr<T, (A, ...)>` is
/// permitted to perform unsynchronized reads from its referent.
pub trait Read<A: Aliasing, R> {}

impl<A: Aliasing, T: ?Sized + crate::Immutable> Read<A, BecauseImmutable> for T {}
impl<T: ?Sized> Read<Exclusive, BecauseExclusive> for T {}
// /// [`Ptr`](crate::Ptr) referents that permit unsynchronized read operations.
// ///
// /// `T: Read<A, R>` implies that a pointer to `T` with aliasing `A` permits
// /// unsynchronized read operations. This can be because `A` is [`Exclusive`] or
// /// because `T` does not permit interior mutation.
// ///
// /// # Safety
// ///
// /// `T: Read<A, R>` if either of the following conditions holds:
// /// - `A` is [`Exclusive`]
// /// - `T` implements [`Immutable`](crate::Immutable)
// ///
// /// As a consequence, if `T: Read<A, R>`, then any `Ptr<T, (A, ...)>` is
// /// permitted to perform unsynchronized reads from its referent.
// pub trait Read<A: Aliasing, R> {}

// impl<A: Aliasing, T: ?Sized + crate::Immutable> Read<A, BecauseImmutable> for T {}
// impl<T: ?Sized> Read<Exclusive, BecauseExclusive> for T {}

/// Unsynchronized reads are permitted because only one live [`Ptr`](crate::Ptr)
/// or reference may exist to the referent bytes at a time.
Expand Down
2 changes: 1 addition & 1 deletion src/pointer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ mod transmute;
pub use {inner::PtrInner, transmute::*};
#[doc(hidden)]
pub use {
invariant::{BecauseExclusive, BecauseImmutable, Read},
invariant::{BecauseExclusive, BecauseImmutable},
ptr::Ptr,
};

Expand Down
42 changes: 25 additions & 17 deletions src/pointer/ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::{
pointer::{
inner::PtrInner,
invariant::*,
transmute::{MutationCompatible, SizeEq, TransmuteFromPtr},
transmute::{SizeEq, TransmuteFromPtr},
},
AlignmentError, CastError, CastType, KnownLayout, SizeError, TryFromBytes, ValidityError,
};
Expand Down Expand Up @@ -580,10 +580,9 @@ mod _conversions {
/// Reads the referent.
#[must_use]
#[inline]
pub fn read_unaligned<R>(self) -> T
pub fn read_unaligned(self) -> T
where
T: Copy,
T: Read<I::Aliasing, R>,
{
(*self.into_unalign().as_ref()).into_inner()
}
Expand Down Expand Up @@ -801,21 +800,19 @@ mod _transitions {
/// On error, unsafe code may rely on this method's returned
/// `ValidityError` containing `self`.
#[inline]
pub(crate) fn try_into_valid<R, S>(
pub(crate) fn try_into_valid<R>(
mut self,
) -> Result<Ptr<'a, T, (I::Aliasing, I::Alignment, Valid)>, ValidityError<Self, T>>
where
T: TryFromBytes
+ Read<I::Aliasing, R>
+ TryTransmuteFromPtr<T, I::Aliasing, I::Validity, Valid, S>,
ReadOnly<T>: Read<I::Aliasing, R>,
T: TryFromBytes + TryTransmuteFromPtr<T, I::Aliasing, I::Validity, Valid, R>,
ReadOnly<T>: TransmuteFromPtr<T, I::Aliasing, Initialized, Initialized, R>,
I::Aliasing: Reference,
I: Invariants<Validity = Initialized>,
{
// This call may panic. If that happens, it doesn't cause any
// soundness issues, as we have not generated any invalid state
// which we need to fix before returning.
if T::is_bit_valid(self.reborrow().transmute::<_, _, _>().reborrow_shared()) {
if T::is_bit_valid(self.reborrow().transmute().reborrow_shared()) {
// SAFETY: If `T::is_bit_valid`, code may assume that `self`
// contains a bit-valid instance of `T`. By `T:
// TryTransmuteFromPtr<T, I::Aliasing, I::Validity, Valid>`, so
Expand Down Expand Up @@ -845,7 +842,10 @@ mod _casts {

use super::*;
use crate::{
pointer::cast::{AsBytesCast, Cast, HasWrappedField, Wrapped},
pointer::{
cast::{AsBytesCast, Cast, HasWrappedField, Wrapped},
TryTransmuteFromPtr,
},
HasField,
};

Expand Down Expand Up @@ -896,7 +896,8 @@ mod _casts {
#[must_use]
pub fn cast<U, C, R>(self) -> Ptr<'a, U, (I::Aliasing, Unaligned, I::Validity)>
where
T: MutationCompatible<U, I::Aliasing, I::Validity, I::Validity, R>,
// T: MutationCompatible<U, I::Aliasing, I::Validity, I::Validity, R>,
U: TransmuteFromPtr<T, I::Aliasing, I::Validity, I::Validity, R>,
U: 'a + ?Sized + CastableFrom<T, I::Validity, I::Validity>,
C: Cast<T, U>,
{
Expand Down Expand Up @@ -992,12 +993,11 @@ mod _casts {
#[inline]
pub fn as_bytes<R>(self) -> Ptr<'a, [u8], (I::Aliasing, Aligned, Valid)>
where
T: Read<I::Aliasing, R>,
[u8]: Read<I::Aliasing, R>,
[u8]: TransmuteFromPtr<T, I::Aliasing, Initialized, Initialized, R>,
I::Aliasing: Reference,
{
let ptr = self.cast::<_, AsBytesCast, _>();
ptr.bikeshed_recall_aligned().recall_validity::<Valid, (_, (_, _))>()
ptr.bikeshed_recall_aligned().recall_validity::<Valid, BecauseImmutable>()
}
}

Expand Down Expand Up @@ -1082,7 +1082,10 @@ mod _casts {
>
where
I::Aliasing: Reference,
U: 'a + ?Sized + KnownLayout + Read<I::Aliasing, R>,
U: 'a
+ ?Sized
+ KnownLayout
+ TryTransmuteFromPtr<[u8], I::Aliasing, Initialized, Initialized, R>,
{
let (inner, remainder) =
self.as_inner().try_cast_into(cast_type, meta).map_err(|err| {
Expand All @@ -1094,6 +1097,8 @@ mod _casts {
unsafe { Ptr::from_inner(inner) })
})?;

// TODO: Update this safety comment for `TryTransmuteFromPtr`.

// SAFETY:
// 0. Since `U: Read<I::Aliasing, _>`, either:
// - `I::Aliasing` is `Exclusive`, in which case both `src` and
Expand Down Expand Up @@ -1145,8 +1150,11 @@ mod _casts {
) -> Result<Ptr<'a, U, (I::Aliasing, Aligned, Initialized)>, CastError<Self, U>>
where
I::Aliasing: Reference,
U: 'a + ?Sized + KnownLayout + Read<I::Aliasing, R>,
[u8]: Read<I::Aliasing, R>,
U: 'a
+ ?Sized
+ KnownLayout
+ TryTransmuteFromPtr<[u8], I::Aliasing, Initialized, Initialized, R>,
[u8]: TransmuteFromPtr<U, I::Aliasing, Initialized, Initialized, R>,
{
// FIXME(#67): Remove this allow. See NonNulSlicelExt for more
// details.
Expand Down
124 changes: 73 additions & 51 deletions src/pointer/transmute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ use crate::{
FromBytes, Immutable, IntoBytes, Unalign,
};

// TODO: We've removed the `SizeEq` super-trait bound.
// - Update this safety documentation to not rely on `SizeEq`.
// - Consider unifying `Ptr::cast` and `Ptr::transmute` - all that separates
// them now is that `transmute` assumes `SizeEq::CastFrom`, while `cast` takes
// an explicit cast argument.

/// Transmutations which are sound to attempt, conditional on validating the bit
/// validity of the destination type.
///
Expand Down Expand Up @@ -101,13 +107,10 @@ use crate::{
/// - The set of `DV`-valid `Dst`s is a superset of the set of `SV`-valid
/// `Src`s. Thus, any value written via `src` is guaranteed to be a `DV`-valid
/// `Dst`.
pub unsafe trait TryTransmuteFromPtr<Src: ?Sized, A: Aliasing, SV: Validity, DV: Validity, R>:
SizeEq<Src>
{
}
pub unsafe trait TryTransmuteFromPtr<Src: ?Sized, A: Aliasing, SV: Validity, DV: Validity, R> {}

#[allow(missing_copy_implementations, missing_debug_implementations)]
pub enum BecauseMutationCompatible {}
// #[allow(missing_copy_implementations, missing_debug_implementations)]
// pub enum BecauseMutationCompatible {}

// TODO: Update this comment to not rely on `SizeEq` implying size equality
// (but instead rely on *runtime execution* of `SizeEq::CastFrom::project`
Expand Down Expand Up @@ -135,16 +138,17 @@ pub enum BecauseMutationCompatible {}
// - `Src: Immutable` and `Dst: Immutable`
// - `Dst: InvariantsEq<Src>`, which guarantees that `Src` and `Dst` have the
// same invariants, and have `UnsafeCell`s covering the same byte ranges
unsafe impl<Src, Dst, SV, DV, A, R>
TryTransmuteFromPtr<Src, A, SV, DV, (BecauseMutationCompatible, R)> for Dst
where
A: Aliasing,
SV: Validity,
DV: Validity,
Src: TransmuteFrom<Dst, DV, SV> + ?Sized,
Dst: MutationCompatible<Src, A, SV, DV, R> + SizeEq<Src> + ?Sized,
{
}

// unsafe impl<Src, Dst, SV, DV, A, R>
// TryTransmuteFromPtr<Src, A, SV, DV, (BecauseMutationCompatible, R)> for Dst
// where
// A: Aliasing,
// SV: Validity,
// DV: Validity,
// Src: TransmuteFrom<Dst, DV, SV> + ?Sized,
// Dst: MutationCompatible<Src, A, SV, DV, R> + SizeEq<Src> + ?Sized,
// {
// }

// SAFETY:
// - Forwards transmutation: Since aliasing is `Shared` and `Src: Immutable`,
Expand All @@ -153,44 +157,62 @@ where
// `dst` does not permit mutation of its referent.
// - No safe code, given access to `src` and `dst`, can cause undefined
// behavior: `Src: Immutable` and `Dst: Immutable`
unsafe impl<Src, Dst, SV, DV> TryTransmuteFromPtr<Src, Shared, SV, DV, BecauseImmutable> for Dst
unsafe impl<Src, Dst, SV, DV, A> TryTransmuteFromPtr<Src, A, SV, DV, BecauseImmutable> for Dst
where
A: Aliasing,
SV: Validity,
DV: Validity,
Src: Immutable + ?Sized,
Dst: Immutable + SizeEq<Src> + ?Sized,
Dst: Immutable + ?Sized,
{
}

/// Denotes that `src: Ptr<Src, (A, _, SV)>` and `dst: Ptr<Self, (A, _, DV)>`,
/// referencing the same referent at the same time, cannot be used by safe code
/// to break library safety invariants of `Src` or `Self`.
///
/// # Safety
///
/// At least one of the following must hold:
/// - `Src: Read<A, _>` and `Self: Read<A, _>`
/// - `Self: InvariantsEq<Src>`, and, for some `V`:
/// - `Dst: TransmuteFrom<Src, V, V>`
/// - `Src: TransmuteFrom<Dst, V, V>`
pub unsafe trait MutationCompatible<Src: ?Sized, A: Aliasing, SV, DV, R> {}

#[allow(missing_copy_implementations, missing_debug_implementations)]
pub enum BecauseRead {}

// TODO: Maybe use the same reason for both? There shouldn't be any situation in
// which the reasons are different (one is BecauseExclusive and the other is
// BecauseImmutable).
// SAFETY: TODO
unsafe impl<Src, Dst, SV, DV> TryTransmuteFromPtr<Src, Exclusive, SV, DV, BecauseExclusive> for Dst
where
SV: Validity,
DV: Validity,
Src: TransmuteFrom<Dst, DV, SV> + ?Sized,
Dst: ?Sized,
{
}

// SAFETY: `Src: Read<A, _>` and `Dst: Read<A, _>`.
unsafe impl<Src: ?Sized, Dst: ?Sized, A: Aliasing, SV: Validity, DV: Validity, R>
MutationCompatible<Src, A, SV, DV, (BecauseRead, R)> for Dst
// SAFETY: TODO
unsafe impl<Src, Dst, SV, DV, A> TryTransmuteFromPtr<Src, A, SV, DV, BecauseInvariantsEq> for Dst
where
Src: Read<A, R>,
Dst: Read<A, R>,
A: Aliasing,
SV: Validity,
DV: Validity,
Src: TransmuteFrom<Dst, DV, SV> + ?Sized,
Dst: TransmuteFrom<Src, SV, DV> + InvariantsEq<Src> + ?Sized,
{
}

// / Denotes that `src: Ptr<Src, (A, _, SV)>` and `dst: Ptr<Self, (A, _, DV)>`,
// / referencing the same referent at the same time, cannot be used by safe code
// / to break library safety invariants of `Src` or `Self`.
// /
// / # Safety
// /
// / At least one of the following must hold:
// / - `Src: Read<A, _>` and `Self: Read<A, _>`
// / - `Self: InvariantsEq<Src>`, and, for some `V`:
// / - `Dst: TransmuteFrom<Src, V, V>`
// / - `Src: TransmuteFrom<Dst, V, V>`
// pub unsafe trait MutationCompatible<Src: ?Sized, A: Aliasing, SV, DV, R> {}

// #[allow(missing_copy_implementations, missing_debug_implementations)]
// pub enum BecauseRead {}

// // SAFETY: `Src: Read<A, _>` and `Dst: Read<A, _>`.
// unsafe impl<Src: ?Sized, Dst: ?Sized, A: Aliasing, SV: Validity, DV: Validity, R>
// MutationCompatible<Src, A, SV, DV, (BecauseRead, R)> for Dst
// where
// Src: Read<A, R>,
// Dst: Read<A, R>,
// {
// }

/// Denotes that two types have the same invariants.
///
/// # Safety
Expand All @@ -203,15 +225,15 @@ pub unsafe trait InvariantsEq<T: ?Sized> {}
// SAFETY: Trivially sound to have multiple `&T` pointing to the same referent.
unsafe impl<T: ?Sized> InvariantsEq<T> for T {}

// SAFETY: `Dst: InvariantsEq<Src> + TransmuteFrom<Src, SV, DV>`, and `Src:
// TransmuteFrom<Dst, DV, SV>`.
unsafe impl<Src: ?Sized, Dst: ?Sized, A: Aliasing, SV: Validity, DV: Validity>
MutationCompatible<Src, A, SV, DV, BecauseInvariantsEq> for Dst
where
Src: TransmuteFrom<Dst, DV, SV>,
Dst: TransmuteFrom<Src, SV, DV> + InvariantsEq<Src>,
{
}
// // SAFETY: `Dst: InvariantsEq<Src> + TransmuteFrom<Src, SV, DV>`, and `Src:
// // TransmuteFrom<Dst, DV, SV>`.
// unsafe impl<Src: ?Sized, Dst: ?Sized, A: Aliasing, SV: Validity, DV: Validity>
// MutationCompatible<Src, A, SV, DV, BecauseInvariantsEq> for Dst
// where
// Src: TransmuteFrom<Dst, DV, SV>,
// Dst: TransmuteFrom<Src, SV, DV> + InvariantsEq<Src>,
// {
// }

#[allow(missing_debug_implementations, missing_copy_implementations)]
#[doc(hidden)]
Expand Down
Loading
Loading