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
23 changes: 5 additions & 18 deletions src/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use core::{
};

use super::*;
use crate::pointer::cast::{CastSizedExact, CastUnsized};

// SAFETY: Per the reference [1], "the unit tuple (`()`) ... is guaranteed as a
// zero-sized type to have a size of 0 and an alignment of 1."
Expand Down Expand Up @@ -108,11 +109,10 @@ assert_unaligned!(bool);
// pattern 0x01.
const _: () = unsafe {
unsafe_impl!(=> TryFromBytes for bool; |byte| {
let byte = byte.transmute::<u8, invariant::Valid, _>();
let byte = byte.transmute_with::<u8, invariant::Valid, CastSizedExact, _>();
*byte.unaligned_as_ref() < 2
})
};
impl_size_eq!(bool, u8);

// SAFETY:
// - `Immutable`: `char` self-evidently does not contain any `UnsafeCell`s.
Expand All @@ -138,14 +138,12 @@ const _: () = unsafe { unsafe_impl!(char: Immutable, FromZeros, IntoBytes) };
// `char`.
const _: () = unsafe {
unsafe_impl!(=> TryFromBytes for char; |c| {
let c = c.transmute::<Unalign<u32>, invariant::Valid, _>();
let c = c.transmute_with::<Unalign<u32>, invariant::Valid, CastSizedExact, _>();
let c = c.read_unaligned().into_inner();
char::from_u32(c).is_some()
});
};

impl_size_eq!(char, Unalign<u32>);

// SAFETY: Per the Reference [1], `str` has the same layout as `[u8]`.
// - `Immutable`: `[u8]` does not contain any `UnsafeCell`s.
// - `FromZeros`, `IntoBytes`, `Unaligned`: `[u8]` is `FromZeros`, `IntoBytes`,
Expand Down Expand Up @@ -173,21 +171,17 @@ const _: () = unsafe { unsafe_impl!(str: Immutable, FromZeros, IntoBytes, Unalig
// Returns `Err` if the slice is not UTF-8.
const _: () = unsafe {
unsafe_impl!(=> TryFromBytes for str; |c| {
let c = c.transmute::<[u8], invariant::Valid, _>();
let c = c.transmute_with::<[u8], invariant::Valid, CastUnsized, _>();
let c = c.unaligned_as_ref();
core::str::from_utf8(c).is_ok()
})
};

impl_size_eq!(str, [u8]);

macro_rules! unsafe_impl_try_from_bytes_for_nonzero {
($($nonzero:ident[$prim:ty]),*) => {
$(
unsafe_impl!(=> TryFromBytes for $nonzero; |n| {
impl_size_eq!($nonzero, Unalign<$prim>);

let n = n.transmute::<Unalign<$prim>, invariant::Valid, _>();
let n = n.transmute_with::<Unalign<$prim>, invariant::Valid, CastSizedExact, _>();
$nonzero::new(n.read_unaligned().into_inner()).is_some()
});
)*
Expand Down Expand Up @@ -425,7 +419,6 @@ mod atomics {
($($($tyvar:ident)? => $atomic:ty [$prim:ty]),*) => {{
crate::util::macros::__unsafe();

use core::cell::UnsafeCell;
use crate::pointer::{SizeEq, TransmuteFrom, invariant::Valid};

$(
Expand All @@ -442,12 +435,6 @@ mod atomics {
impl<$($tyvar)?> SizeEq<$prim> for $atomic {
type CastFrom = $crate::pointer::cast::CastSizedExact;
}
impl<$($tyvar)?> SizeEq<$atomic> for UnsafeCell<$prim> {
type CastFrom = $crate::pointer::cast::CastSizedExact;
}
impl<$($tyvar)?> SizeEq<UnsafeCell<$prim>> for $atomic {
type CastFrom = $crate::pointer::cast::CastSizedExact;
}

// SAFETY: The caller promised that `$atomic` and `$prim` have
// the same bit validity. `UnsafeCell<T>` has the same bit
Expand Down
26 changes: 19 additions & 7 deletions src/pointer/ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -382,11 +382,20 @@ mod _conversions {
where
V: Validity,
U: TransmuteFromPtr<T, I::Aliasing, I::Validity, V, R> + SizeEq<T> + ?Sized,
{
self.transmute_with::<U, V, <U as SizeEq<T>>::CastFrom, R>()
}

pub(crate) fn transmute_with<U, V, C, R>(self) -> Ptr<'a, U, (I::Aliasing, Unaligned, V)>
where
V: Validity,
U: TransmuteFromPtr<T, I::Aliasing, I::Validity, V, R> + ?Sized,
C: crate::pointer::cast::CastExact<T, U>,
{
// SAFETY:
// - By `SizeEq::CastFrom: Cast`, `SizeEq::CastFrom` preserves
// referent address, and so we don't need to consider projections
// in the following safety arguments.
// - By `C: CastExact`, `C` preserves referent address, and so we
// don't need to consider projections in the following safety
// arguments.
// - If aliasing is `Shared`, then by `U: TransmuteFromPtr<T>`, at
// least one of the following holds:
// - `T: Immutable` and `U: Immutable`, in which case it is
Expand All @@ -395,8 +404,10 @@ mod _conversions {
// - It is directly guaranteed that it is sound for shared code to
// operate on these references simultaneously
// - By `U: TransmuteFromPtr<T, I::Aliasing, I::Validity, V>`, it is
// sound to perform this transmute.
unsafe { self.project_transmute_unchecked::<_, _, <U as SizeEq<T>>::CastFrom>() }
// sound to perform this transmute using an address- and
// size-preserving cast. By `C: CastExact`, `C` is address- and
// size-preserving.
unsafe { self.project_transmute_unchecked::<_, _, C>() }
}

#[doc(hidden)]
Expand All @@ -414,9 +425,10 @@ mod _conversions {
// - It is trivially sound to have multiple `&T` referencing the
// same referent simultaneously
// - By `T: TransmuteFromPtr<T, I::Aliasing, I::Validity, V>`, it is
// sound to perform this transmute.
// sound to perform this transmute using an address- and
// size-preserving cast (which `IdCast` is).
let ptr =
unsafe { self.project_transmute_unchecked::<_, _, <T as SizeEq<T>>::CastFrom>() };
unsafe { self.project_transmute_unchecked::<_, _, crate::pointer::cast::IdCast>() };
// SAFETY: `self` and `ptr` have the same address and referent type.
// Therefore, if `self` satisfies `I::Alignment`, then so does
// `ptr`.
Expand Down
48 changes: 18 additions & 30 deletions src/pointer/transmute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ use crate::{
///
/// Given `src: Ptr<'a, Src, (A, _, SV)>`, if the referent of `src` is
/// `DV`-valid for `Dst`, then it is sound to transmute `src` into `dst: Ptr<'a,
/// Dst, (A, Unaligned, DV)>` using `<Dst as SizeEq<Src>>::CastFrom::project`.
/// Dst, (A, Unaligned, DV)>` using a address- and size-preserving cast.
///
/// ## Pre-conditions
///
Expand Down Expand Up @@ -67,17 +67,14 @@ use crate::{
/// Given:
/// - `src: Ptr<'a, Src, (A, _, SV)>`
/// - `src`'s referent is `DV`-valid for `Dst`
/// - `Dst: SizeEq<Src>`
///
/// We are trying to prove that it is sound to cast using `<Dst as
/// SizeEq<Src>>::CastFrom::project` from `src` to a `dst: Ptr<'a, Dst, (A,
/// Unaligned, DV)>`. We need to prove that such a transmute does not violate
/// any of `src`'s invariants, and that it satisfies all invariants of the
/// destination `Ptr` type.
/// We are trying to prove that it is sound to perform a size-preserving cast
/// from `src` to a `dst: Ptr<'a, Dst, (A, Unaligned, DV)>`. We need to prove
/// that such a cast does not violate any of `src`'s invariants, and that it
/// satisfies all invariants of the destination `Ptr` type.
///
/// First, by `SizeEq::CastFrom: CastExact`, `src`'s address is unchanged, so it
/// still satisfies its alignment. Since `dst`'s alignment is `Unaligned`, it
/// trivially satisfies its alignment.
/// First, `src`'s address is unchanged, so it still satisfies its alignment.
/// Since `dst`'s alignment is `Unaligned`, it trivially satisfies its alignment.
///
/// Second, aliasing is either `Exclusive` or `Shared`:
/// - If it is `Exclusive`, then both `src` and `dst` satisfy `Exclusive`
Expand Down Expand Up @@ -106,10 +103,7 @@ use crate::{
/// - The set of `DV`-valid referents of `dst` is a superset of the set of
/// `SV`-valid referents of `src`. Thus, any value written via `src` is
/// guaranteed to be a `DV`-valid referent of `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 {}
Expand All @@ -123,14 +117,14 @@ pub enum BecauseMutationCompatible {}
// exists, no mutation is permitted except via that `Ptr`
// - Aliasing is `Shared`, `Src: Immutable`, and `Dst: Immutable`, in which
// case no mutation is possible via either `Ptr`
// - Since the underlying cast is performed using `<Dst as SizeEq<Src>>
// ::CastFrom::project`, `dst` addresses the same bytes as `src`. By `Dst:
// TransmuteFrom<Src, SV, DV>`, the set of `DV`-valid referents of `dst` is a
// supserset of the set of `SV`-valid referents of `src`.
// - Reverse transmutation: Since the underlying cast is performed using `<Dst
// as SizeEq<Src>>::CastFrom::project`, `dst` addresses the same bytes as
// `src`. By `Src: TransmuteFrom<Dst, DV, SV>`, the set of `DV`-valid
// referents of `dst` is a subset of the set of `SV`-valid referents of `src`.
// - Since the underlying cast is size-preserving, `dst` addresses the same
// bytes as `src`. By `Dst: TransmuteFrom<Src, SV, DV>`, the set of
// `DV`-valid referents of `dst` is a superset of the set of `SV`-valid
// referents of `src`.
// - Reverse transmutation: Since the underlying cast is size-preserving, `dst`
// addresses the same bytes as `src`. By `Src: TransmuteFrom<Dst, DV, SV>`, the
// set of `DV`-valid referents of `src` is a subset of the set of `SV`-valid
// referents of `dst`.
// - No safe code, given access to `src` and `dst`, can cause undefined
// behavior: By `Dst: MutationCompatible<Src, A, SV, DV, _>`, at least one of
// the following holds:
Expand All @@ -145,7 +139,7 @@ where
SV: Validity,
DV: Validity,
Src: TransmuteFrom<Dst, DV, SV> + ?Sized,
Dst: MutationCompatible<Src, A, SV, DV, R> + SizeEq<Src> + ?Sized,
Dst: MutationCompatible<Src, A, SV, DV, R> + ?Sized,
{
}

Expand All @@ -161,7 +155,7 @@ where
SV: Validity,
DV: Validity,
Src: Immutable + ?Sized,
Dst: Immutable + SizeEq<Src> + ?Sized,
Dst: Immutable + ?Sized,
{
}

Expand Down Expand Up @@ -505,11 +499,5 @@ mod tests {

// 2. Prim -> Atomic (SizeEq<Prim> for Atomic)
test_size_eq::<u8, AtomicU8>(0u8);

// 3. Atomic -> UnsafeCell<Prim> (SizeEq<Atomic> for UnsafeCell<Prim>)
test_size_eq::<AtomicU8, UnsafeCell<u8>>(AtomicU8::new(0));

// 4. UnsafeCell<Prim> -> Atomic (SizeEq<UnsafeCell<Prim>> for Atomic)
test_size_eq::<UnsafeCell<u8>, AtomicU8>(UnsafeCell::new(0u8));
}
}
16 changes: 0 additions & 16 deletions src/util/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -797,22 +797,6 @@ macro_rules! impl_transitive_transmute_from {
};
}

#[rustfmt::skip]
macro_rules! impl_size_eq {
($t:ty, $u:ty) => {
const _: () = {
use $crate::{pointer::{cast::CastUnsized, SizeEq}};

impl SizeEq<$t> for $u {
type CastFrom = CastUnsized;
}
impl SizeEq<$u> for $t {
type CastFrom = CastUnsized;
}
};
};
}

/// Invokes `$blk` in a context in which `$src<$t>` and `$dst<$u>` implement
/// `SizeEq`.
///
Expand Down
Loading