zerocopy/pointer/
transmute.rs

1// Copyright 2025 The Fuchsia Authors
2//
3// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
4// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
5// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
6// This file may not be copied, modified, or distributed except according to
7// those terms.
8
9use core::{
10    cell::{Cell, UnsafeCell},
11    mem::{ManuallyDrop, MaybeUninit},
12    num::Wrapping,
13    ptr::NonNull,
14};
15
16use crate::{pointer::invariant::*, FromBytes, Immutable, IntoBytes, Unalign};
17
18/// Transmutations which are sound to attempt, conditional on validating the bit
19/// validity of the destination type.
20///
21/// If a `Ptr` transmutation is `TryTransmuteFromPtr`, then it is sound to
22/// perform that transmutation so long as some additional mechanism is used to
23/// validate that the referent is bit-valid for the destination type. That
24/// validation mechanism could be a type bound (such as `TransmuteFrom`) or a
25/// runtime validity check.
26///
27/// # Safety
28///
29/// ## Post-conditions
30///
31/// Given `Dst: TryTransmuteFromPtr<Src, A, SV, DV, _>`, callers may assume the
32/// following:
33///
34/// Given `src: Ptr<'a, Src, (A, _, SV)>`, if the referent of `src` is
35/// `DV`-valid for `Dst`, then it is sound to transmute `src` into `dst: Ptr<'a,
36/// Dst, (A, Unaligned, DV)>` by preserving pointer address and metadata.
37///
38/// ## Pre-conditions
39///
40/// Given `src: Ptr<Src, (A, _, SV)>` and `dst: Ptr<Dst, (A, Unaligned, DV)>`,
41/// `Dst: TryTransmuteFromPtr<Src, A, SV, DV, _>` is sound if all of the
42/// following hold:
43/// - Forwards transmutation: Either of the following hold:
44///   - So long as `dst` is active, no mutation of `dst`'s referent is allowed
45///     except via `dst` itself
46///   - The set of `DV`-valid `Dst`s is a superset of the set of `SV`-valid
47///     `Src`s
48/// - Reverse transmutation: Either of the following hold:
49///   - `dst` does not permit mutation of its referent
50///   - The set of `DV`-valid `Dst`s is a subset of the set of `SV`-valid `Src`s
51/// - No safe code, given access to `src` and `dst`, can cause undefined
52///   behavior: Any of the following hold:
53///   - `A` is `Exclusive`
54///   - `Src: Immutable` and `Dst: Immutable`
55///   - It is sound for shared code to operate on a `&Src` and `&Dst` which
56///     reference the same byte range at the same time
57///
58/// ## Proof
59///
60/// Given:
61/// - `src: Ptr<'a, Src, (A, _, SV)>`
62/// - `src`'s referent is `DV`-valid for `Dst`
63/// - `Dst: SizeEq<Src>`
64///
65/// We are trying to prove that it is sound to perform a pointer address- and
66/// metadata-preserving transmute from `src` to a `dst: Ptr<'a, Dst, (A,
67/// Unaligned, DV)>`. We need to prove that such a transmute does not violate
68/// any of `src`'s invariants, and that it satisfies all invariants of the
69/// destination `Ptr` type.
70///
71/// First, all of `src`'s `PtrInner` invariants are upheld. `src`'s address and
72/// metadata are unchanged, so:
73/// - If its referent is not zero sized, then it still has valid provenance for
74///   its referent, which is still entirely contained in some Rust allocation,
75///   `A`
76/// - If its referent is not zero sized, `A` is guaranteed to live for at least
77///   `'a`
78///
79/// Since `Dst: SizeEq<Src>`, and since `dst` has the same address and metadata
80/// as `src`, `dst` addresses the same byte range as `src`. `dst` also has the
81/// same lifetime as `src`. Therefore, all of the `PtrInner` invariants
82/// mentioned above also hold for `dst`.
83///
84/// Second, since `src`'s address is unchanged, it still satisfies its
85/// alignment. Since `dst`'s alignment is `Unaligned`, it trivially satisfies
86/// its alignment.
87///
88/// Third, aliasing is either `Exclusive` or `Shared`:
89/// - If it is `Exclusive`, then both `src` and `dst` satisfy `Exclusive`
90///   aliasing trivially: since `src` and `dst` have the same lifetime, `src` is
91///   inaccessible so long as `dst` is alive, and no other live `Ptr`s or
92///   references may reference the same referent.
93/// - If it is `Shared`, then either:
94///   - `Src: Immutable` and `Dst: Immutable`, and so `UnsafeCell`s trivially
95///     cover the same byte ranges in both types.
96///   - It is explicitly sound for safe code to operate on a `&Src` and a `&Dst`
97///     pointing to the same byte range at the same time.
98///
99/// Fourth, `src`'s validity is satisfied. By invariant, `src`'s referent began
100/// as an `SV`-valid `Src`. It is guaranteed to remain so, as either of the
101/// following hold:
102/// - `dst` does not permit mutation of its referent.
103/// - The set of `DV`-valid `Dst`s is a superset of the set of `SV`-valid
104///   `Src`s. Thus, any value written via `dst` is guaranteed to be `SV`-valid
105///   for `Src`.
106///
107/// Fifth, `dst`'s validity is satisfied. It is a given of this proof that the
108/// referent is `DV`-valid for `Dst`. It is guaranteed to remain so, as either
109/// of the following hold:
110/// - So long as `dst` is active, no mutation of the referent is allowed except
111///   via `dst` itself.
112/// - The set of `DV`-valid `Dst`s is a superset of the set of `SV`-valid
113///   `Src`s. Thus, any value written via `src` is guaranteed to be a `DV`-valid
114///   `Dst`.
115pub unsafe trait TryTransmuteFromPtr<Src: ?Sized, A: Aliasing, SV: Validity, DV: Validity, R>:
116    SizeEq<Src>
117{
118}
119
120#[allow(missing_copy_implementations, missing_debug_implementations)]
121pub enum BecauseMutationCompatible {}
122
123// SAFETY:
124// - Forwards transmutation: By `Dst: MutationCompatible<Src, A, SV, DV, _>`, we
125//   know that at least one of the following holds:
126//   - So long as `dst: Ptr<Dst>` is active, no mutation of its referent is
127//     allowed except via `dst` itself if either of the following hold:
128//     - Aliasing is `Exclusive`, in which case, so long as the `Dst` `Ptr`
129//       exists, no mutation is permitted except via that `Ptr`
130//     - Aliasing is `Shared`, `Src: Immutable`, and `Dst: Immutable`, in which
131//       case no mutation is possible via either `Ptr`
132//   - `Dst: TransmuteFrom<Src, SV, DV>`, and so the set of `DV`-valid `Dst`s is
133//     a supserset of the set of `SV`-valid `Src`s
134// - Reverse transmutation: `Src: TransmuteFrom<Dst, DV, SV>`, and so the set of
135//   `DV`-valid `Dst`s is a subset of the set of `SV`-valid `Src`s
136// - No safe code, given access to `src` and `dst`, can cause undefined
137//   behavior: By `Dst: MutationCompatible<Src, A, SV, DV, _>`, at least one of
138//   the following holds:
139//   - `A` is `Exclusive`
140//   - `Src: Immutable` and `Dst: Immutable`
141//   - `Dst: InvariantsEq<Src>`, which guarantees that `Src` and `Dst` have the
142//     same invariants, and have `UnsafeCell`s covering the same byte ranges
143unsafe impl<Src, Dst, SV, DV, A, R>
144    TryTransmuteFromPtr<Src, A, SV, DV, (BecauseMutationCompatible, R)> for Dst
145where
146    A: Aliasing,
147    SV: Validity,
148    DV: Validity,
149    Src: TransmuteFrom<Dst, DV, SV> + ?Sized,
150    Dst: MutationCompatible<Src, A, SV, DV, R> + SizeEq<Src> + ?Sized,
151{
152}
153
154// SAFETY:
155// - Forwards transmutation: Since aliasing is `Shared` and `Src: Immutable`,
156//   `src` does not permit mutation of its referent.
157// - Reverse transmutation: Since aliasing is `Shared` and `Dst: Immutable`,
158//   `dst` does not permit mutation of its referent.
159// - No safe code, given access to `src` and `dst`, can cause undefined
160//   behavior: `Src: Immutable` and `Dst: Immutable`
161unsafe impl<Src, Dst, SV, DV> TryTransmuteFromPtr<Src, Shared, SV, DV, BecauseImmutable> for Dst
162where
163    SV: Validity,
164    DV: Validity,
165    Src: Immutable + ?Sized,
166    Dst: Immutable + SizeEq<Src> + ?Sized,
167{
168}
169
170/// Denotes that `src: Ptr<Src, (A, _, SV)>` and `dst: Ptr<Self, (A, _, DV)>`,
171/// referencing the same referent at the same time, cannot be used by safe code
172/// to break library safety invariants of `Src` or `Self`.
173///
174/// # Safety
175///
176/// At least one of the following must hold:
177/// - `Src: Read<A, _>` and `Self: Read<A, _>`
178/// - `Self: InvariantsEq<Src>`, and, for some `V`:
179///   - `Dst: TransmuteFrom<Src, V, V>`
180///   - `Src: TransmuteFrom<Dst, V, V>`
181pub unsafe trait MutationCompatible<Src: ?Sized, A: Aliasing, SV, DV, R> {}
182
183#[allow(missing_copy_implementations, missing_debug_implementations)]
184pub enum BecauseRead {}
185
186// SAFETY: `Src: Read<A, _>` and `Dst: Read<A, _>`.
187unsafe impl<Src: ?Sized, Dst: ?Sized, A: Aliasing, SV: Validity, DV: Validity, R, S>
188    MutationCompatible<Src, A, SV, DV, (BecauseRead, (R, S))> for Dst
189where
190    Src: Read<A, R>,
191    Dst: Read<A, S>,
192{
193}
194
195/// Denotes that two types have the same invariants.
196///
197/// # Safety
198///
199/// It is sound for safe code to operate on a `&T` and a `&Self` pointing to the
200/// same referent at the same time - no such safe code can cause undefined
201/// behavior.
202pub unsafe trait InvariantsEq<T: ?Sized> {}
203
204// SAFETY: Trivially sound to have multiple `&T` pointing to the same referent.
205unsafe impl<T: ?Sized> InvariantsEq<T> for T {}
206
207// SAFETY: `Dst: InvariantsEq<Src> + TransmuteFrom<Src, V, V>`, and `Src:
208// TransmuteFrom<Dst, V, V>`.
209unsafe impl<Src: ?Sized, Dst: ?Sized, A: Aliasing, V: Validity>
210    MutationCompatible<Src, A, V, V, BecauseInvariantsEq> for Dst
211where
212    Src: TransmuteFrom<Dst, V, V>,
213    Dst: TransmuteFrom<Src, V, V> + InvariantsEq<Src>,
214{
215}
216
217pub(crate) enum BecauseInvariantsEq {}
218
219macro_rules! unsafe_impl_invariants_eq {
220    ($tyvar:ident => $t:ty, $u:ty) => {
221        unsafe impl<$tyvar> InvariantsEq<$t> for $u {}
222        unsafe impl<$tyvar> InvariantsEq<$u> for $t {}
223    };
224}
225
226impl_transitive_transmute_from!(T => MaybeUninit<T> => T => Wrapping<T>);
227impl_transitive_transmute_from!(T => Wrapping<T> => T => MaybeUninit<T>);
228
229// SAFETY: `ManuallyDrop<T>` has the same size and bit validity as `T` [1], and
230// implements `Deref<Target = T>` [2]. Thus, it is already possible for safe
231// code to obtain a `&T` and a `&ManuallyDrop<T>` to the same referent at the
232// same time.
233//
234// [1] Per https://doc.rust-lang.org/1.81.0/std/mem/struct.ManuallyDrop.html:
235//
236//   `ManuallyDrop<T>` is guaranteed to have the same layout and bit
237//   validity as `T`
238//
239// [2] https://doc.rust-lang.org/1.81.0/std/mem/struct.ManuallyDrop.html#impl-Deref-for-ManuallyDrop%3CT%3E
240unsafe impl<T: ?Sized> InvariantsEq<T> for ManuallyDrop<T> {}
241// SAFETY: See previous safety comment.
242unsafe impl<T: ?Sized> InvariantsEq<ManuallyDrop<T>> for T {}
243
244/// Transmutations which are always sound.
245///
246/// `TransmuteFromPtr` is a shorthand for [`TryTransmuteFromPtr`] and
247/// [`TransmuteFrom`].
248///
249/// # Safety
250///
251/// `Dst: TransmuteFromPtr<Src, A, SV, DV, _>` is equivalent to `Dst:
252/// TryTransmuteFromPtr<Src, A, SV, DV, _> + TransmuteFrom<Src, SV, DV>`.
253pub unsafe trait TransmuteFromPtr<Src: ?Sized, A: Aliasing, SV: Validity, DV: Validity, R>:
254    TryTransmuteFromPtr<Src, A, SV, DV, R> + TransmuteFrom<Src, SV, DV>
255{
256}
257
258// SAFETY: The `where` bounds are equivalent to the safety invariant on
259// `TransmuteFromPtr`.
260unsafe impl<Src: ?Sized, Dst: ?Sized, A: Aliasing, SV: Validity, DV: Validity, R>
261    TransmuteFromPtr<Src, A, SV, DV, R> for Dst
262where
263    Dst: TransmuteFrom<Src, SV, DV> + TryTransmuteFromPtr<Src, A, SV, DV, R>,
264{
265}
266
267/// Denotes that any `SV`-valid `Src` may soundly be transmuted into a
268/// `DV`-valid `Self`.
269///
270/// # Safety
271///
272/// The set of bit patterns allowed to appear in the referent of a `Ptr<Src, (_,
273/// _, SV)>` must be a subset of the set allowed to appear in the referent of a
274/// `Ptr<Self, (_, _, DV)>`.
275pub unsafe trait TransmuteFrom<Src: ?Sized, SV, DV>: SizeEq<Src> {}
276
277/// # Safety
278///
279/// `T` and `Self` must have the same vtable kind (`Sized`, slice DST, `dyn`,
280/// etc) and have the same size. In particular:
281/// - If `T: Sized` and `Self: Sized`, then their sizes must be equal
282/// - If `T: ?Sized` and `Self: ?Sized`, then it must be the case that, given
283///   any `t: *mut T`, `t as *mut Self` produces a pointer which addresses the
284///   same number of bytes as `t`.
285pub unsafe trait SizeEq<T: ?Sized> {
286    fn cast_from_raw(t: NonNull<T>) -> NonNull<Self>;
287}
288
289// SAFETY: `T` trivially has the same size and vtable kind as `T`, and since
290// pointer `*mut T -> *mut T` pointer casts are no-ops, this cast trivially
291// preserves referent size (when `T: ?Sized`).
292unsafe impl<T: ?Sized> SizeEq<T> for T {
293    fn cast_from_raw(t: NonNull<T>) -> NonNull<T> {
294        t
295    }
296}
297
298// SAFETY: Since `Src: IntoBytes`, the set of valid `Src`'s is the set of
299// initialized bit patterns, which is exactly the set allowed in the referent of
300// any `Initialized` `Ptr`.
301unsafe impl<Src, Dst> TransmuteFrom<Src, Valid, Initialized> for Dst
302where
303    Src: IntoBytes + ?Sized,
304    Dst: SizeEq<Src> + ?Sized,
305{
306}
307
308// SAFETY: Since `Dst: FromBytes`, any initialized bit pattern may appear in the
309// referent of a `Ptr<Dst, (_, _, Valid)>`. This is exactly equal to the set of
310// bit patterns which may appear in the referent of any `Initialized` `Ptr`.
311unsafe impl<Src, Dst> TransmuteFrom<Src, Initialized, Valid> for Dst
312where
313    Src: ?Sized,
314    Dst: FromBytes + SizeEq<Src> + ?Sized,
315{
316}
317
318// TODO(#2354): This seems like a smell - the soundness of this bound has
319// nothing to do with `Src` or `Dst` - we're basically just saying `[u8; N]` is
320// transmutable into `[u8; N]`.
321
322// SAFETY: The set of allowed bit patterns in the referent of any `Initialized`
323// `Ptr` is the same regardless of referent type.
324unsafe impl<Src, Dst> TransmuteFrom<Src, Initialized, Initialized> for Dst
325where
326    Src: ?Sized,
327    Dst: SizeEq<Src> + ?Sized,
328{
329}
330
331// TODO(#2354): This seems like a smell - the soundness of this bound has
332// nothing to do with `Dst` - we're basically just saying that any type is
333// transmutable into `MaybeUninit<[u8; N]>`.
334
335// SAFETY: A `Dst` with validity `Uninit` permits any byte sequence, and
336// therefore can be transmuted from any value.
337unsafe impl<Src, Dst, V> TransmuteFrom<Src, V, Uninit> for Dst
338where
339    Src: ?Sized,
340    Dst: SizeEq<Src> + ?Sized,
341    V: Validity,
342{
343}
344
345safety_comment! {
346    /// SAFETY:
347    /// - `ManuallyDrop<T>` has the same size as `T` [1]
348    /// - `ManuallyDrop<T>` has the same validity as `T` [1]
349    ///
350    /// [1] Per https://doc.rust-lang.org/1.81.0/std/mem/struct.ManuallyDrop.html:
351    ///
352    ///   `ManuallyDrop<T>` is guaranteed to have the same layout and bit
353    ///   validity as `T`
354    unsafe_impl_for_transparent_wrapper!(T: ?Sized => ManuallyDrop<T>);
355
356    /// SAFETY:
357    /// - `Unalign<T>` promises to have the same size as `T`.
358    /// - `Unalign<T>` promises to have the same validity as `T`.
359    unsafe_impl_for_transparent_wrapper!(T => Unalign<T>);
360    /// SAFETY:
361    /// `Unalign<T>` promises to have the same size and validity as `T`. Given
362    /// `u: &Unalign<T>`, it is already possible to obtain `let t =
363    /// u.try_deref().unwrap()`. Because `Unalign<T>` has the same size as `T`,
364    /// the returned `&T` must point to the same referent as `u`, and thus it
365    /// must be sound for these two references to exist at the same time since
366    /// it's already possible for safe code to get into this state.
367    unsafe_impl_invariants_eq!(T => T, Unalign<T>);
368
369    /// SAFETY:
370    /// - `Wrapping<T>` has the same size as `T` [1].
371    /// - `Wrapping<T>` has only one field, which is `pub` [2]. We are also
372    ///   guaranteed per that `Wrapping<T>` has the same layout as `T` [1]. The
373    ///   only way for both of these to be true simultaneously is for
374    ///   `Wrapping<T>` to have the same bit validity as `T`. In particular, in
375    ///   order to change the bit validity, one of the following would need to
376    ///   happen:
377    ///   - `Wrapping` could change its `repr`, but this would violate the
378    ///     layout guarantee.
379    ///   - `Wrapping` could add or change its fields, but this would be a
380    ///     stability-breaking change.
381    ///
382    /// [1] Per https://doc.rust-lang.org/1.85.0/core/num/struct.Wrapping.html#layout-1:
383    ///
384    ///   `Wrapping<T>` is guaranteed to have the same layout and ABI as `T`.
385    ///
386    /// [2] Definition from https://doc.rust-lang.org/1.85.0/core/num/struct.Wrapping.html:
387    ///
388    ///   ```
389    ///   #[repr(transparent)]
390    ///   pub struct Wrapping<T>(pub T);
391    ///   ```
392    unsafe_impl_for_transparent_wrapper!(T => Wrapping<T>);
393    /// SAFETY:
394    /// By the preceding safety proof, `Wrapping<T>` and `T` have the same
395    /// layout and bit validity. Since a `Wrapping<T>`'s `T` field is `pub`,
396    /// given `w: &Wrapping<T>`, it's possible to do `let t = &w.t`, which means
397    /// that it's already possible for safe code to obtain a `&Wrapping<T>` and
398    /// a `&T` pointing to the same referent at the same time. Thus, this must
399    /// be sound.
400    unsafe_impl_invariants_eq!(T => T, Wrapping<T>);
401
402    /// SAFETY:
403    /// - `UnsafeCell<T>` has the same size as `T` [1].
404    /// - Per [1], `UnsafeCell<T>` has the same bit validity as `T`. Technically
405    ///   the term "representation" doesn't guarantee this, but the subsequent
406    ///   sentence in the documentation makes it clear that this is the
407    ///   intention.
408    ///
409    /// [1] Per https://doc.rust-lang.org/1.81.0/core/cell/struct.UnsafeCell.html#memory-layout:
410    ///
411    ///   `UnsafeCell<T>` has the same in-memory representation as its inner
412    ///   type `T`. A consequence of this guarantee is that it is possible to
413    ///   convert between `T` and `UnsafeCell<T>`.
414    unsafe_impl_for_transparent_wrapper!(T: ?Sized => UnsafeCell<T>);
415
416    /// SAFETY:
417    /// - `Cell<T>` has the same size as `T` [1].
418    /// - Per [1], `Cell<T>` has the same bit validity as `T`. Technically the
419    ///   term "representation" doesn't guarantee this, but it does promise to
420    ///   have the "same memory layout and caveats as `UnsafeCell<T>`." The
421    ///   `UnsafeCell` docs [2] make it clear that bit validity is the intention
422    ///   even if that phrase isn't used.
423    ///
424    /// [1] Per https://doc.rust-lang.org/1.85.0/std/cell/struct.Cell.html#memory-layout:
425    ///
426    ///   `Cell<T>` has the same memory layout and caveats as `UnsafeCell<T>`.
427    ///   In particular, this means that `Cell<T>` has the same in-memory
428    ///   representation as its inner type `T`.
429    ///
430    /// [2] Per https://doc.rust-lang.org/1.81.0/core/cell/struct.UnsafeCell.html#memory-layout:
431    ///
432    ///   `UnsafeCell<T>` has the same in-memory representation as its inner
433    ///   type `T`. A consequence of this guarantee is that it is possible to
434    ///   convert between `T` and `UnsafeCell<T>`.
435    unsafe_impl_for_transparent_wrapper!(T: ?Sized => Cell<T>);
436}
437
438impl_transitive_transmute_from!(T: ?Sized => Cell<T> => T => UnsafeCell<T>);
439impl_transitive_transmute_from!(T: ?Sized => UnsafeCell<T> => T => Cell<T>);
440
441// SAFETY: `MaybeUninit<T>` has no validity requirements. Currently this is not
442// explicitly guaranteed, but it's obvious from `MaybeUninit`'s documentation
443// that this is the intention:
444// https://doc.rust-lang.org/1.85.0/core/mem/union.MaybeUninit.html
445unsafe impl<T> TransmuteFrom<T, Uninit, Valid> for MaybeUninit<T> {}
446
447// SAFETY: `MaybeUninit<T>` has the same size as `T` [1].
448//
449// [1] Per https://doc.rust-lang.org/1.81.0/std/mem/union.MaybeUninit.html#layout-1:
450//
451//   `MaybeUninit<T>` is guaranteed to have the same size, alignment, and ABI as
452//   `T`
453unsafe impl<T> SizeEq<T> for MaybeUninit<T> {
454    fn cast_from_raw(t: NonNull<T>) -> NonNull<MaybeUninit<T>> {
455        cast!(t)
456    }
457}
458
459// SAFETY: See previous safety comment.
460unsafe impl<T> SizeEq<MaybeUninit<T>> for T {
461    fn cast_from_raw(t: NonNull<MaybeUninit<T>>) -> NonNull<T> {
462        cast!(t)
463    }
464}