summaryrefslogtreecommitdiff
path: root/rust/zerocopy/src/pointer/transmute.rs
diff options
context:
space:
mode:
Diffstat (limited to 'rust/zerocopy/src/pointer/transmute.rs')
-rw-r--r--rust/zerocopy/src/pointer/transmute.rs100
1 files changed, 54 insertions, 46 deletions
diff --git a/rust/zerocopy/src/pointer/transmute.rs b/rust/zerocopy/src/pointer/transmute.rs
index ef9836698203..75f9312f622e 100644
--- a/rust/zerocopy/src/pointer/transmute.rs
+++ b/rust/zerocopy/src/pointer/transmute.rs
@@ -24,14 +24,14 @@ use crate::{
FromBytes, Immutable, IntoBytes, Unalign,
};
-/// Transmutations which are sound to attempt, conditional on validating the bit
-/// validity of the destination type.
+/// Exact pointer reinterpretations which are sound to attempt, conditional on
+/// establishing the destination validity invariant.
///
/// If a `Ptr` transmutation is `TryTransmuteFromPtr`, then it is sound to
/// perform that transmutation so long as some additional mechanism is used to
-/// validate that the referent is bit-valid for the destination type. That
-/// validation mechanism could be a type bound (such as `TransmuteFrom`) or a
-/// runtime validity check.
+/// establish that the referent is `DV`-valid for the destination type. That
+/// mechanism could be a type bound (such as `TransmuteFrom`) or a runtime
+/// validity check.
///
/// # Safety
///
@@ -49,14 +49,14 @@ use crate::{
/// Given `src: Ptr<Src, (A, _, SV)>` and `dst: Ptr<Dst, (A, Unaligned, DV)>`,
/// `Dst: TryTransmuteFromPtr<Src, A, SV, DV, C, _>` is sound if all of the
/// following hold:
-/// - Forwards transmutation: Either of the following hold:
+/// - Preserve destination validity: Either of the following hold:
/// - So long as `dst` is active, no mutation of `dst`'s referent is allowed
/// except via `dst` itself
/// - The set of `DV`-valid referents of `dst` is a superset of the set of
/// `SV`-valid referents of `src` (NOTE: this condition effectively bans
/// shrinking or overwriting transmutes, which cannot satisfy this
/// condition)
-/// - Reverse transmutation: Either of the following hold:
+/// - Preserve source validity: Either of the following hold:
/// - `dst` does not permit mutation of its referent
/// - The set of `DV`-valid referents of `dst` is a subset of the set of
/// `SV`-valid referents of `src` (NOTE: this condition effectively bans
@@ -126,7 +126,7 @@ pub unsafe trait TryTransmuteFromPtr<
pub enum BecauseMutationCompatible {}
// SAFETY:
-// - Forwards transmutation: By `Dst: MutationCompatible<Src, A, SV, DV, _>`, we
+// - Preserve destination validity: By `Dst: MutationCompatible<Src, A, SV, DV, _>`, we
// know that at least one of the following holds:
// - So long as `dst: Ptr<Dst>` is active, no mutation of its referent is
// allowed except via `dst` itself if either of the following hold:
@@ -138,17 +138,18 @@ pub enum BecauseMutationCompatible {}
// referent 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 referent 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`.
+// - Preserve source validity: Since the underlying cast is size-preserving,
+// `dst` addresses the same referent 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`.
// - 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:
// - `A` is `Exclusive`
// - `Src: Immutable` and `Dst: Immutable`
-// - `Dst: InvariantsEq<Src>`, which guarantees that `Src` and `Dst` have the
-// same invariants, and permit interior mutation on the same byte ranges
+// - `Dst: SharedCompatible<Src>`, which guarantees that it is sound for safe
+// code to operate on `&Src` and `&Dst` pointing to the same byte range at
+// the same time
unsafe impl<Src, Dst, SV, DV, A, C, R>
TryTransmuteFromPtr<Src, A, SV, DV, C, (BecauseMutationCompatible, R)> for Dst
where
@@ -162,9 +163,9 @@ where
}
// SAFETY:
-// - Forwards transmutation: Since aliasing is `Shared` and `Src: Immutable`,
+// - Preserve destination validity: Since aliasing is `Shared` and `Src: Immutable`,
// `src` does not permit mutation of its referent.
-// - Reverse transmutation: Since aliasing is `Shared` and `Dst: Immutable`,
+// - Preserve source validity: Since aliasing is `Shared` and `Dst: Immutable`,
// `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`
@@ -187,9 +188,9 @@ where
///
/// 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>`
+/// - `Self: SharedCompatible<Src>`, and, for some `V`:
+/// - `Self: TransmuteFrom<Src, V, V>`
+/// - `Src: TransmuteFrom<Self, V, V>`
pub unsafe trait MutationCompatible<Src: ?Sized, A: Aliasing, SV, DV, R> {}
#[allow(missing_copy_implementations, missing_debug_implementations)]
@@ -204,38 +205,39 @@ where
{
}
-/// Denotes that two types have the same invariants.
+/// Denotes that shared references to two types may safely coexist on the same
+/// referent.
///
/// # Safety
///
/// It is sound for safe code to operate on a `&T` and a `&Self` pointing to the
/// same referent at the same time - no such safe code can cause undefined
/// behavior.
-pub unsafe trait InvariantsEq<T: ?Sized> {}
+pub unsafe trait SharedCompatible<T: ?Sized> {}
// SAFETY: Trivially sound to have multiple `&T` pointing to the same referent.
-unsafe impl<T: ?Sized> InvariantsEq<T> for T {}
+unsafe impl<T: ?Sized> SharedCompatible<T> for T {}
-// SAFETY: `Dst: InvariantsEq<Src> + TransmuteFrom<Src, SV, DV>`, and `Src:
+// SAFETY: `Dst: SharedCompatible<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
+ MutationCompatible<Src, A, SV, DV, BecauseSharedCompatible> for Dst
where
Src: TransmuteFrom<Dst, DV, SV>,
- Dst: TransmuteFrom<Src, SV, DV> + InvariantsEq<Src>,
+ Dst: TransmuteFrom<Src, SV, DV> + SharedCompatible<Src>,
{
}
#[allow(missing_debug_implementations, missing_copy_implementations)]
-pub enum BecauseInvariantsEq {}
+pub enum BecauseSharedCompatible {}
-macro_rules! unsafe_impl_invariants_eq {
+macro_rules! unsafe_impl_shared_compatible {
($tyvar:ident => $t:ty, $u:ty) => {{
crate::util::macros::__unsafe();
// SAFETY: The caller promises that this is sound.
- unsafe impl<$tyvar> InvariantsEq<$t> for $u {}
+ unsafe impl<$tyvar> SharedCompatible<$t> for $u {}
// SAFETY: The caller promises that this is sound.
- unsafe impl<$tyvar> InvariantsEq<$u> for $t {}
+ unsafe impl<$tyvar> SharedCompatible<$u> for $t {}
}};
}
@@ -253,11 +255,11 @@ impl_transitive_transmute_from!(T => Wrapping<T> => T => MaybeUninit<T>);
// validity as `T`
//
// [2] https://doc.rust-lang.org/1.81.0/std/mem/struct.ManuallyDrop.html#impl-Deref-for-ManuallyDrop%3CT%3E
-unsafe impl<T: ?Sized> InvariantsEq<T> for ManuallyDrop<T> {}
+unsafe impl<T: ?Sized> SharedCompatible<T> for ManuallyDrop<T> {}
// SAFETY: See previous safety comment.
-unsafe impl<T: ?Sized> InvariantsEq<ManuallyDrop<T>> for T {}
+unsafe impl<T: ?Sized> SharedCompatible<ManuallyDrop<T>> for T {}
-/// Transmutations which are always sound.
+/// Exact pointer reinterpretations which are always sound.
///
/// `TransmuteFromPtr` is a shorthand for [`TryTransmuteFromPtr`] and
/// [`TransmuteFrom`].
@@ -293,8 +295,12 @@ where
{
}
-/// Denotes that any `SV`-valid `Src` may soundly be transmuted into a
-/// `DV`-valid `Self`.
+/// Denotes that, for equally-sized referents, every bit pattern allowed for an
+/// `SV`-valid `Src` is also allowed for a `DV`-valid `Self`.
+///
+/// `TransmuteFrom` does not by itself authorize a pointer transmutation. It
+/// provides a directional validity implication used by the pointer-transmutation
+/// machinery.
///
/// # Safety
///
@@ -333,7 +339,7 @@ impl<T: ?Sized> SizeEq<T> for T {
// SAFETY: Since `Src: IntoBytes`, the set of valid `Src`'s is the set of
// initialized bit patterns, which is exactly the set allowed in the referent of
// any `Initialized` `Ptr`.
-unsafe impl<Src, Dst> TransmuteFrom<Src, Valid, Initialized> for Dst
+unsafe impl<Src, Dst> TransmuteFrom<Src, Safe, Initialized> for Dst
where
Src: IntoBytes + ?Sized,
Dst: ?Sized,
@@ -341,18 +347,19 @@ where
}
// SAFETY: Since `Dst: FromBytes`, any initialized bit pattern may appear in the
-// referent of a `Ptr<Dst, (_, _, Valid)>`. This is exactly equal to the set of
+// referent of a `Ptr<Dst, (_, _, Safe)>`. This is exactly equal to the set of
// bit patterns which may appear in the referent of any `Initialized` `Ptr`.
-unsafe impl<Src, Dst> TransmuteFrom<Src, Initialized, Valid> for Dst
+unsafe impl<Src, Dst> TransmuteFrom<Src, Initialized, Safe> for Dst
where
Src: ?Sized,
Dst: FromBytes + ?Sized,
{
}
-// FIXME(#2354): This seems like a smell - the soundness of this bound has
-// nothing to do with `Src` or `Dst` - we're basically just saying `[u8; N]` is
-// transmutable into `[u8; N]`.
+// FIXME(#2354): This relation does not depend on `Src` or `Dst`. That is
+// expected semantically: `Initialized` permits the same states regardless of
+// referent type. The awkward part is encoding that validity-state relation as a
+// trait relation between referent types.
// SAFETY: The set of allowed bit patterns in the referent of any `Initialized`
// `Ptr` is the same regardless of referent type.
@@ -363,9 +370,10 @@ where
{
}
-// FIXME(#2354): This seems like a smell - the soundness of this bound has
-// nothing to do with `Dst` - we're basically just saying that any type is
-// transmutable into `MaybeUninit<[u8; N]>`.
+// FIXME(#2354): This relation does not depend on `Src` or `Dst`. That is
+// expected semantically: every validity state implies `Uninit`, which permits
+// any byte sequence. The awkward part is encoding that validity-state relation
+// as a trait relation between referent types.
// SAFETY: A `Dst` with validity `Uninit` permits any byte sequence, and
// therefore can be transmuted from any value.
@@ -400,7 +408,7 @@ const _: () = unsafe { unsafe_impl_for_transparent_wrapper!(pub T => Unalign<T>)
// sound for these two references to exist at the same time since it's already
// possible for safe code to get into this state.
#[allow(clippy::multiple_unsafe_ops_per_block)]
-const _: () = unsafe { unsafe_impl_invariants_eq!(T => T, Unalign<T>) };
+const _: () = unsafe { unsafe_impl_shared_compatible!(T => T, Unalign<T>) };
// SAFETY:
// - `Wrapping<T>` has the same size as `T` [1].
@@ -433,7 +441,7 @@ const _: () = unsafe { unsafe_impl_for_transparent_wrapper!(pub T => Wrapping<T>
// already possible for safe code to obtain a `&Wrapping<T>` and a `&T` pointing
// to the same referent at the same time. Thus, this must be sound.
#[allow(clippy::multiple_unsafe_ops_per_block)]
-const _: () = unsafe { unsafe_impl_invariants_eq!(T => T, Wrapping<T>) };
+const _: () = unsafe { unsafe_impl_shared_compatible!(T => T, Wrapping<T>) };
// SAFETY:
// - `UnsafeCell<T>` has the same size as `T` [1].
@@ -478,7 +486,7 @@ impl_transitive_transmute_from!(T: ?Sized => UnsafeCell<T> => T => Cell<T>);
// explicitly guaranteed, but it's obvious from `MaybeUninit`'s documentation
// that this is the intention:
// https://doc.rust-lang.org/1.85.0/core/mem/union.MaybeUninit.html
-unsafe impl<T> TransmuteFrom<T, Uninit, Valid> for MaybeUninit<T> {}
+unsafe impl<T> TransmuteFrom<T, Uninit, Safe> for MaybeUninit<T> {}
impl<T> SizeEq<T> for MaybeUninit<T> {
type CastFrom = CastSizedExact;