zerocopy/pointer/
mod.rs

1// Copyright 2023 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
9//! Abstractions over raw pointers.
10
11mod inner;
12#[doc(hidden)]
13pub mod invariant;
14mod ptr;
15mod transmute;
16
17#[doc(hidden)]
18pub use {inner::PtrInner, transmute::*};
19#[doc(hidden)]
20pub use {
21    invariant::{BecauseExclusive, BecauseImmutable, Read},
22    ptr::Ptr,
23};
24
25/// A shorthand for a maybe-valid, maybe-aligned reference. Used as the argument
26/// to [`TryFromBytes::is_bit_valid`].
27///
28/// [`TryFromBytes::is_bit_valid`]: crate::TryFromBytes::is_bit_valid
29pub type Maybe<'a, T, Aliasing = invariant::Shared, Alignment = invariant::Unaligned> =
30    Ptr<'a, T, (Aliasing, Alignment, invariant::Initialized)>;
31
32/// Checks if the referent is zeroed.
33pub(crate) fn is_zeroed<T, I>(ptr: Ptr<'_, T, I>) -> bool
34where
35    T: crate::Immutable + crate::KnownLayout,
36    I: invariant::Invariants<Validity = invariant::Initialized>,
37    I::Aliasing: invariant::Reference,
38{
39    ptr.as_bytes::<BecauseImmutable>().as_ref().iter().all(|&byte| byte == 0)
40}
41
42#[doc(hidden)]
43pub mod cast {
44    use core::{marker::PhantomData, mem};
45
46    use crate::{
47        layout::{SizeInfo, TrailingSliceLayout},
48        HasField, KnownLayout, PtrInner,
49    };
50
51    /// A pointer cast or projection.
52    ///
53    /// # Safety
54    ///
55    /// The implementation of `project` must satisfy its safety post-condition.
56    pub unsafe trait Project<Src: ?Sized, Dst: ?Sized> {
57        /// Projects a pointer from `Src` to `Dst`.
58        ///
59        /// # Safety
60        ///
61        /// The returned pointer refers to a non-strict subset of the bytes of
62        /// `src`'s referent, and has the same provenance as `src`.
63        fn project(src: PtrInner<'_, Src>) -> *mut Dst;
64    }
65
66    /// A [`Project`] which preserves the address of the referent – a pointer
67    /// cast.
68    ///
69    /// # Safety
70    ///
71    /// A `Cast` projection must preserve the address of the referent. It may
72    /// shrink the set of referent bytes, and it may change the referent's type.
73    pub unsafe trait Cast<Src: ?Sized, Dst: ?Sized>: Project<Src, Dst> {}
74
75    /// A no-op pointer cast.
76    #[derive(Default, Copy, Clone)]
77    #[allow(missing_debug_implementations)]
78    pub struct IdCast;
79
80    // SAFETY: `project` returns its argument unchanged, and so it is a
81    // provenance-preserving projection which preserves the set of referent
82    // bytes.
83    unsafe impl<T: ?Sized> Project<T, T> for IdCast {
84        #[inline(always)]
85        fn project(src: PtrInner<'_, T>) -> *mut T {
86            src.as_ptr()
87        }
88    }
89
90    // SAFETY: The `Project::project` impl preserves referent address.
91    unsafe impl<T: ?Sized> Cast<T, T> for IdCast {}
92
93    /// A pointer cast which preserves or shrinks the set of referent bytes of
94    /// a statically-sized referent.
95    ///
96    /// # Safety
97    ///
98    /// The implementation of [`Project`] uses a compile-time assertion to
99    /// guarantee that `Dst` is no larger than `Src`. Thus, `CastSized` has a
100    /// sound implementation of [`Project`] for all `Src` and `Dst` – the caller
101    /// may pass any `Src` and `Dst` without being responsible for soundness.
102    #[allow(missing_debug_implementations, missing_copy_implementations)]
103    pub enum CastSized {}
104
105    // SAFETY: By the `static_assert!`, `Dst` is no larger than `Src`,
106    // and so all casts preserve or shrink the set of referent bytes. All
107    // operations preserve provenance.
108    unsafe impl<Src, Dst> Project<Src, Dst> for CastSized {
109        #[inline(always)]
110        fn project(src: PtrInner<'_, Src>) -> *mut Dst {
111            static_assert!(Src, Dst => mem::size_of::<Src>() >= mem::size_of::<Dst>());
112            src.as_ptr().cast::<Dst>()
113        }
114    }
115
116    // SAFETY: The `Project::project` impl preserves referent address.
117    unsafe impl<Src, Dst> Cast<Src, Dst> for CastSized {}
118
119    /// A pointer cast which preserves or shrinks the set of referent bytes of
120    /// a dynamically-sized referent.
121    ///
122    /// # Safety
123    ///
124    /// The implementation of [`Project`] uses a compile-time assertion to
125    /// guarantee that the cast preserves the set of referent bytes. Thus,
126    /// `CastUnsized` has a sound implementation of [`Project`] for all `Src`
127    /// and `Dst` – the caller may pass any `Src` and `Dst` without being
128    /// responsible for soundness.
129    #[allow(missing_debug_implementations, missing_copy_implementations)]
130    pub enum CastUnsized {}
131
132    // SAFETY: The `static_assert!` ensures that `Src` and `Dst` have the same
133    // `SizeInfo`. Thus, casting preserves the set of referent bytes. All
134    // operations are provenance-preserving.
135    unsafe impl<Src, Dst> Project<Src, Dst> for CastUnsized
136    where
137        Src: ?Sized + KnownLayout,
138        Dst: ?Sized + KnownLayout<PointerMetadata = Src::PointerMetadata>,
139    {
140        #[inline(always)]
141        fn project(src: PtrInner<'_, Src>) -> *mut Dst {
142            // FIXME:
143            // - Is the alignment check necessary for soundness? It's not
144            //   necessary for the soundness of the `Project` impl, but what
145            //   about the soundness of particular use sites?
146            // - Do we want this to support shrinking casts as well?
147            static_assert!(Src: ?Sized + KnownLayout, Dst: ?Sized + KnownLayout => {
148                let t = <Src as KnownLayout>::LAYOUT;
149                let u = <Dst as KnownLayout>::LAYOUT;
150                t.align.get() >= u.align.get() && match (t.size_info, u.size_info) {
151                    (SizeInfo::Sized { size: t }, SizeInfo::Sized { size: u }) => t == u,
152                    (
153                        SizeInfo::SliceDst(TrailingSliceLayout { offset: t_offset, elem_size: t_elem_size }),
154                        SizeInfo::SliceDst(TrailingSliceLayout { offset: u_offset, elem_size: u_elem_size })
155                    ) => t_offset == u_offset && t_elem_size == u_elem_size,
156                    _ => false,
157                }
158            });
159
160            let metadata = Src::pointer_to_metadata(src.as_ptr());
161            Dst::raw_from_ptr_len(src.as_non_null().cast::<u8>(), metadata).as_ptr()
162        }
163    }
164
165    // SAFETY: The `Project::project` impl preserves referent address.
166    unsafe impl<Src, Dst> Cast<Src, Dst> for CastUnsized
167    where
168        Src: ?Sized + KnownLayout,
169        Dst: ?Sized + KnownLayout<PointerMetadata = Src::PointerMetadata>,
170    {
171    }
172
173    /// A field projection
174    ///
175    /// A `Projection` is a [`Project`] which implements projection by
176    /// delegating to an implementation of [`HasField::project`].
177    #[allow(missing_debug_implementations, missing_copy_implementations)]
178    pub struct Projection<F: ?Sized, const VARIANT_ID: i128, const FIELD_ID: i128> {
179        _never: core::convert::Infallible,
180        _phantom: PhantomData<F>,
181    }
182
183    // SAFETY: `HasField::project` has the same safety post-conditions as
184    // `Project::project`.
185    unsafe impl<T: ?Sized, F, const VARIANT_ID: i128, const FIELD_ID: i128> Project<T, T::Type>
186        for Projection<F, VARIANT_ID, FIELD_ID>
187    where
188        T: HasField<F, VARIANT_ID, FIELD_ID>,
189    {
190        #[inline(always)]
191        fn project(src: PtrInner<'_, T>) -> *mut T::Type {
192            T::project(src)
193        }
194    }
195
196    /// A transitive sequence of projections.
197    ///
198    /// Given `TU: Project` and `UV: Project`, `TransitiveProject<_, TU, UV>` is
199    /// a [`Project`] which projects by applying `TU` followed by `UV`.
200    ///
201    /// If `TU: Cast` and `UV: Cast`, then `TransitiveProject<_, TU, UV>: Cast`.
202    #[allow(missing_debug_implementations)]
203    pub struct TransitiveProject<U: ?Sized, TU, UV> {
204        _never: core::convert::Infallible,
205        _projections: PhantomData<(TU, UV)>,
206        // On our MSRV (1.56), the debuginfo for a tuple containing both an
207        // uninhabited type and a DST causes an ICE. We split `U` from `TU` and
208        // `UV` to avoid this situation.
209        _u: PhantomData<U>,
210    }
211
212    // SAFETY: Since `TU::project` and `UV::project` are each
213    // provenance-preserving operations which preserve or shrink the set of
214    // referent bytes, so is their composition.
215    unsafe impl<T, U, V, TU, UV> Project<T, V> for TransitiveProject<U, TU, UV>
216    where
217        T: ?Sized,
218        U: ?Sized,
219        V: ?Sized,
220        TU: Project<T, U>,
221        UV: Project<U, V>,
222    {
223        #[inline(always)]
224        fn project(t: PtrInner<'_, T>) -> *mut V {
225            t.project::<_, TU>().project::<_, UV>().as_ptr()
226        }
227    }
228
229    // SAFETY: Since the `Project::project` impl delegates to `TU::project` and
230    // `UV::project`, and since `TU` and `UV` are `Cast`, the `Project::project`
231    // impl preserves the address of the referent.
232    unsafe impl<T, U, V, TU, UV> Cast<T, V> for TransitiveProject<U, TU, UV>
233    where
234        T: ?Sized,
235        U: ?Sized,
236        V: ?Sized,
237        TU: Cast<T, U>,
238        UV: Cast<U, V>,
239    {
240    }
241
242    /// A cast from `T` to `[u8]`.
243    pub(crate) struct AsBytesCast;
244
245    // SAFETY: `project` constructs a pointer with the same address as `src`
246    // and with a referent of the same size as `*src`. It does this using
247    // provenance-preserving operations.
248    //
249    // FIXME(https://github.com/rust-lang/unsafe-code-guidelines/issues/594):
250    // Technically, this proof assumes that `*src` is contiguous (the same is
251    // true of other proofs in this codebase). Is this guaranteed anywhere?
252    unsafe impl<T: ?Sized + KnownLayout> Project<T, [u8]> for AsBytesCast {
253        #[inline(always)]
254        fn project(src: PtrInner<'_, T>) -> *mut [u8] {
255            let bytes = match T::size_of_val_raw(src.as_non_null()) {
256                Some(bytes) => bytes,
257                // SAFETY: `KnownLayout::size_of_val_raw` promises to always
258                // return `Some` so long as the resulting size fits in a
259                // `usize`. By invariant on `PtrInner`, `src` refers to a range
260                // of bytes whose size fits in an `isize`, which implies that it
261                // also fits in a `usize`.
262                None => unsafe { core::hint::unreachable_unchecked() },
263            };
264
265            core::ptr::slice_from_raw_parts_mut(src.as_ptr().cast::<u8>(), bytes)
266        }
267    }
268
269    // SAFETY: The `Project::project` impl preserves referent address.
270    unsafe impl<T: ?Sized + KnownLayout> Cast<T, [u8]> for AsBytesCast {}
271}