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::*,
23};
24
25use crate::wrappers::ReadOnly;
26
27/// A shorthand for a maybe-valid, maybe-aligned reference. Used as the argument
28/// to [`TryFromBytes::is_bit_valid`].
29///
30/// [`TryFromBytes::is_bit_valid`]: crate::TryFromBytes::is_bit_valid
31pub type Maybe<'a, T, Alignment = invariant::Unaligned> =
32 Ptr<'a, ReadOnly<T>, (invariant::Shared, Alignment, invariant::Initialized)>;
33
34/// Checks if the referent is zeroed.
35pub(crate) fn is_zeroed<T, I>(ptr: Ptr<'_, T, I>) -> bool
36where
37 T: crate::Immutable + crate::KnownLayout,
38 I: invariant::Invariants<Validity = invariant::Initialized>,
39 I::Aliasing: invariant::Reference,
40{
41 ptr.as_bytes().as_ref().iter().all(
42 #[inline(always)]
43 |&byte| byte == 0,
44 )
45}
46
47#[doc(hidden)]
48pub mod cast {
49 use core::{marker::PhantomData, mem};
50
51 use crate::{
52 layout::{SizeInfo, TrailingSliceLayout},
53 HasField, KnownLayout, PtrInner,
54 };
55
56 /// A pointer cast or projection.
57 ///
58 /// # Safety
59 ///
60 /// The implementation of `project` must satisfy its safety post-condition.
61 pub unsafe trait Project<Src: ?Sized, Dst: ?Sized> {
62 /// Projects a pointer from `Src` to `Dst`.
63 ///
64 /// Users should generally not call `project` directly, and instead
65 /// should use high-level APIs like [`PtrInner::project`] or
66 /// [`Ptr::project`].
67 ///
68 /// [`Ptr::project`]: crate::pointer::Ptr::project
69 ///
70 /// # Safety
71 ///
72 /// The returned pointer refers to a non-strict subset of the bytes of
73 /// `src`'s referent, and has the same provenance as `src`.
74 fn project(src: PtrInner<'_, Src>) -> *mut Dst;
75 }
76
77 /// A [`Project`] which preserves the address of the referent – a pointer
78 /// cast.
79 ///
80 /// # Safety
81 ///
82 /// A `Cast` projection must preserve the address of the referent. It may
83 /// shrink the set of referent bytes, and it may change the referent's type.
84 pub unsafe trait Cast<Src: ?Sized, Dst: ?Sized>: Project<Src, Dst> {}
85
86 /// A [`Cast`] which does not shrink the set of referent bytes.
87 ///
88 /// # Safety
89 ///
90 /// A `CastExact` projection must preserve the set of referent bytes.
91 pub unsafe trait CastExact<Src: ?Sized, Dst: ?Sized>: Cast<Src, Dst> {}
92
93 /// A no-op pointer cast.
94 #[derive(Default, Copy, Clone)]
95 #[allow(missing_debug_implementations)]
96 pub struct IdCast;
97
98 // SAFETY: `project` returns its argument unchanged, and so it is a
99 // provenance-preserving projection which preserves the set of referent
100 // bytes.
101 unsafe impl<T: ?Sized> Project<T, T> for IdCast {
102 #[inline(always)]
103 fn project(src: PtrInner<'_, T>) -> *mut T {
104 src.as_ptr()
105 }
106 }
107
108 // SAFETY: The `Project::project` impl preserves referent address.
109 unsafe impl<T: ?Sized> Cast<T, T> for IdCast {}
110
111 // SAFETY: The `Project::project` impl preserves referent size.
112 unsafe impl<T: ?Sized> CastExact<T, T> for IdCast {}
113
114 /// A pointer cast which preserves or shrinks the set of referent bytes of
115 /// a statically-sized referent.
116 ///
117 /// # Safety
118 ///
119 /// The implementation of [`Project`] uses a compile-time assertion to
120 /// guarantee that `Dst` is no larger than `Src`. Thus, `CastSized` has a
121 /// sound implementation of [`Project`] for all `Src` and `Dst` – the caller
122 /// may pass any `Src` and `Dst` without being responsible for soundness.
123 #[allow(missing_debug_implementations, missing_copy_implementations)]
124 pub enum CastSized {}
125
126 // SAFETY: By the `static_assert!`, `Dst` is no larger than `Src`,
127 // and so all casts preserve or shrink the set of referent bytes. All
128 // operations preserve provenance.
129 unsafe impl<Src, Dst> Project<Src, Dst> for CastSized {
130 #[inline(always)]
131 fn project(src: PtrInner<'_, Src>) -> *mut Dst {
132 static_assert!(Src, Dst => mem::size_of::<Src>() >= mem::size_of::<Dst>());
133 src.as_ptr().cast::<Dst>()
134 }
135 }
136
137 // SAFETY: The `Project::project` impl preserves referent address.
138 unsafe impl<Src, Dst> Cast<Src, Dst> for CastSized {}
139
140 /// A pointer cast which preserves the set of referent bytes of a
141 /// statically-sized referent.
142 ///
143 /// # Safety
144 ///
145 /// The implementation of [`Project`] uses a compile-time assertion to
146 /// guarantee that `Dst` has the same size as `Src`. Thus, `CastSizedExact`
147 /// has a sound implementation of [`Project`] for all `Src` and `Dst` – the
148 /// caller may pass any `Src` and `Dst` without being responsible for
149 /// soundness.
150 #[allow(missing_debug_implementations, missing_copy_implementations)]
151 pub enum CastSizedExact {}
152
153 // SAFETY: By the `static_assert!`, `Dst` has the same size as `Src`,
154 // and so all casts preserve the set of referent bytes. All operations
155 // preserve provenance.
156 unsafe impl<Src, Dst> Project<Src, Dst> for CastSizedExact {
157 #[inline(always)]
158 fn project(src: PtrInner<'_, Src>) -> *mut Dst {
159 static_assert!(Src, Dst => mem::size_of::<Src>() == mem::size_of::<Dst>());
160 src.as_ptr().cast::<Dst>()
161 }
162 }
163
164 // SAFETY: The `Project::project_raw` impl preserves referent address.
165 unsafe impl<Src, Dst> Cast<Src, Dst> for CastSizedExact {}
166
167 // SAFETY: By the `static_assert!`, `Project::project_raw` impl preserves
168 // referent size.
169 unsafe impl<Src, Dst> CastExact<Src, Dst> for CastSizedExact {}
170
171 /// A pointer cast which preserves or shrinks the set of referent bytes of
172 /// a dynamically-sized referent.
173 ///
174 /// # Safety
175 ///
176 /// The implementation of [`Project`] uses a compile-time assertion to
177 /// guarantee that the cast preserves the set of referent bytes. Thus,
178 /// `CastUnsized` has a sound implementation of [`Project`] for all `Src`
179 /// and `Dst` – the caller may pass any `Src` and `Dst` without being
180 /// responsible for soundness.
181 #[allow(missing_debug_implementations, missing_copy_implementations)]
182 pub enum CastUnsized {}
183
184 // SAFETY: By the `static_assert!`, `Src` and `Dst` are either:
185 // - Both sized and equal in size
186 // - Both slice DSTs with the same trailing slice offset and element size
187 // and with align_of::<Src>() == align_of::<Dst>(). These ensure that any
188 // given pointer metadata encodes the same size for both `Src` and `Dst`
189 // (note that the alignment is required as it affects the amount of
190 // trailing padding). Thus, `project` preserves the set of referent bytes.
191 unsafe impl<Src, Dst> Project<Src, Dst> for CastUnsized
192 where
193 Src: ?Sized + KnownLayout,
194 Dst: ?Sized + KnownLayout<PointerMetadata = Src::PointerMetadata>,
195 {
196 #[inline(always)]
197 fn project(src: PtrInner<'_, Src>) -> *mut Dst {
198 // FIXME: Do we want this to support shrinking casts as well? If so,
199 // we'll need to remove the `CastExact` impl.
200 static_assert!(Src: ?Sized + KnownLayout, Dst: ?Sized + KnownLayout => {
201 let src = <Src as KnownLayout>::LAYOUT;
202 let dst = <Dst as KnownLayout>::LAYOUT;
203 match (src.size_info, dst.size_info) {
204 (SizeInfo::Sized { size: src_size }, SizeInfo::Sized { size: dst_size }) => src_size == dst_size,
205 (
206 SizeInfo::SliceDst(TrailingSliceLayout { offset: src_offset, elem_size: src_elem_size }),
207 SizeInfo::SliceDst(TrailingSliceLayout { offset: dst_offset, elem_size: dst_elem_size })
208 ) => src.align.get() == dst.align.get() && src_offset == dst_offset && src_elem_size == dst_elem_size,
209 _ => false,
210 }
211 });
212
213 let metadata = Src::pointer_to_metadata(src.as_ptr());
214 Dst::raw_from_ptr_len(src.as_non_null().cast::<u8>(), metadata).as_ptr()
215 }
216 }
217
218 // SAFETY: The `Project::project` impl preserves referent address.
219 unsafe impl<Src, Dst> Cast<Src, Dst> for CastUnsized
220 where
221 Src: ?Sized + KnownLayout,
222 Dst: ?Sized + KnownLayout<PointerMetadata = Src::PointerMetadata>,
223 {
224 }
225
226 // SAFETY: By the `static_assert!` in `Project::project`, `Src` and `Dst`
227 // are either:
228 // - Both sized and equal in size
229 // - Both slice DSTs with the same alignment, trailing slice offset, and
230 // element size. These ensure that any given pointer metadata encodes the
231 // same size for both `Src` and `Dst` (note that the alignment is required
232 // as it affects the amount of trailing padding).
233 unsafe impl<Src, Dst> CastExact<Src, Dst> for CastUnsized
234 where
235 Src: ?Sized + KnownLayout,
236 Dst: ?Sized + KnownLayout<PointerMetadata = Src::PointerMetadata>,
237 {
238 }
239
240 /// A field projection
241 ///
242 /// A `Projection` is a [`Project`] which implements projection by
243 /// delegating to an implementation of [`HasField::project`].
244 #[allow(missing_debug_implementations, missing_copy_implementations)]
245 pub struct Projection<F: ?Sized, const VARIANT_ID: i128, const FIELD_ID: i128> {
246 _never: core::convert::Infallible,
247 _phantom: PhantomData<F>,
248 }
249
250 // SAFETY: `HasField::project` has the same safety post-conditions as
251 // `Project::project`.
252 unsafe impl<T: ?Sized, F, const VARIANT_ID: i128, const FIELD_ID: i128> Project<T, T::Type>
253 for Projection<F, VARIANT_ID, FIELD_ID>
254 where
255 T: HasField<F, VARIANT_ID, FIELD_ID>,
256 {
257 #[inline(always)]
258 fn project(src: PtrInner<'_, T>) -> *mut T::Type {
259 T::project(src)
260 }
261 }
262
263 // SAFETY: All `repr(C)` union fields exist at offset 0 within the union [1],
264 // and so any union projection is actually a cast (ie, preserves address).
265 //
266 // [1] Per
267 // https://doc.rust-lang.org/1.92.0/reference/type-layout.html#reprc-unions,
268 // it's not *technically* guaranteed that non-maximally-sized fields
269 // are at offset 0, but it's clear that this is the intention of `repr(C)`
270 // unions. It says:
271 //
272 // > A union declared with `#[repr(C)]` will have the same size and
273 // > alignment as an equivalent C union declaration in the C language for
274 // > the target platform.
275 //
276 // Note that this only mentions size and alignment, not layout. However,
277 // C unions *do* guarantee that all fields start at offset 0. [2]
278 //
279 // This is also reinforced by
280 // https://doc.rust-lang.org/1.92.0/reference/items/unions.html#r-items.union.fields.offset:
281 //
282 // > Fields might have a non-zero offset (except when the C
283 // > representation is used); in that case the bits starting at the
284 // > offset of the fields are read
285 //
286 // [2] Per https://port70.net/~nsz/c/c11/n1570.html#6.7.2.1p16:
287 //
288 // > The size of a union is sufficient to contain the largest of its
289 // > members. The value of at most one of the members can be stored in a
290 // > union object at any time. A pointer to a union object, suitably
291 // > converted, points to each of its members (or if a member is a
292 // > bit-field, then to the unit in which it resides), and vice versa.
293 //
294 // FIXME(https://github.com/rust-lang/unsafe-code-guidelines/issues/595):
295 // Cite the documentation once it's updated.
296 unsafe impl<T: ?Sized, F, const FIELD_ID: i128> Cast<T, T::Type>
297 for Projection<F, { crate::REPR_C_UNION_VARIANT_ID }, FIELD_ID>
298 where
299 T: HasField<F, { crate::REPR_C_UNION_VARIANT_ID }, FIELD_ID>,
300 {
301 }
302
303 /// A transitive sequence of projections.
304 ///
305 /// Given `TU: Project` and `UV: Project`, `TransitiveProject<_, TU, UV>` is
306 /// a [`Project`] which projects by applying `TU` followed by `UV`.
307 ///
308 /// If `TU: Cast` and `UV: Cast`, then `TransitiveProject<_, TU, UV>: Cast`.
309 #[allow(missing_debug_implementations)]
310 pub struct TransitiveProject<U: ?Sized, TU, UV> {
311 _never: core::convert::Infallible,
312 _projections: PhantomData<(TU, UV)>,
313 // On our MSRV (1.56), the debuginfo for a tuple containing both an
314 // uninhabited type and a DST causes an ICE. We split `U` from `TU` and
315 // `UV` to avoid this situation.
316 _u: PhantomData<U>,
317 }
318
319 // SAFETY: Since `TU::project` and `UV::project` are each
320 // provenance-preserving operations which preserve or shrink the set of
321 // referent bytes, so is their composition.
322 unsafe impl<T, U, V, TU, UV> Project<T, V> for TransitiveProject<U, TU, UV>
323 where
324 T: ?Sized,
325 U: ?Sized,
326 V: ?Sized,
327 TU: Project<T, U>,
328 UV: Project<U, V>,
329 {
330 #[inline(always)]
331 fn project(t: PtrInner<'_, T>) -> *mut V {
332 t.project::<_, TU>().project::<_, UV>().as_ptr()
333 }
334 }
335
336 // SAFETY: Since the `Project::project` impl delegates to `TU::project` and
337 // `UV::project`, and since `TU` and `UV` are `Cast`, the `Project::project`
338 // impl preserves the address of the referent.
339 unsafe impl<T, U, V, TU, UV> Cast<T, V> for TransitiveProject<U, TU, UV>
340 where
341 T: ?Sized,
342 U: ?Sized,
343 V: ?Sized,
344 TU: Cast<T, U>,
345 UV: Cast<U, V>,
346 {
347 }
348
349 // SAFETY: Since the `Project::project` impl delegates to `TU::project` and
350 // `UV::project`, and since `TU` and `UV` are `CastExact`, the `Project::project`
351 // impl preserves the set of referent bytes.
352 unsafe impl<T, U, V, TU, UV> CastExact<T, V> for TransitiveProject<U, TU, UV>
353 where
354 T: ?Sized,
355 U: ?Sized,
356 V: ?Sized,
357 TU: CastExact<T, U>,
358 UV: CastExact<U, V>,
359 {
360 }
361
362 /// A cast from `T` to `[u8]`.
363 #[allow(missing_copy_implementations, missing_debug_implementations)]
364 pub struct AsBytesCast;
365
366 // SAFETY: `project` constructs a pointer with the same address as `src`
367 // and with a referent of the same size as `*src`. It does this using
368 // provenance-preserving operations.
369 //
370 // FIXME(https://github.com/rust-lang/unsafe-code-guidelines/issues/594):
371 // Technically, this proof assumes that `*src` is contiguous (the same is
372 // true of other proofs in this codebase). Is this guaranteed anywhere?
373 unsafe impl<T: ?Sized + KnownLayout> Project<T, [u8]> for AsBytesCast {
374 #[inline(always)]
375 fn project(src: PtrInner<'_, T>) -> *mut [u8] {
376 let bytes = match T::size_of_val_raw(src.as_non_null()) {
377 Some(bytes) => bytes,
378 // SAFETY: `KnownLayout::size_of_val_raw` promises to always
379 // return `Some` so long as the resulting size fits in a
380 // `usize`. By invariant on `PtrInner`, `src` refers to a range
381 // of bytes whose size fits in an `isize`, which implies that it
382 // also fits in a `usize`.
383 None => unsafe { core::hint::unreachable_unchecked() },
384 };
385
386 core::ptr::slice_from_raw_parts_mut(src.as_ptr().cast::<u8>(), bytes)
387 }
388 }
389
390 // SAFETY: The `Project::project` impl preserves referent address.
391 unsafe impl<T: ?Sized + KnownLayout> Cast<T, [u8]> for AsBytesCast {}
392
393 // SAFETY: The `Project::project` impl preserves the set of referent bytes.
394 unsafe impl<T: ?Sized + KnownLayout> CastExact<T, [u8]> for AsBytesCast {}
395
396 /// A cast from any type to `()`.
397 #[allow(missing_copy_implementations, missing_debug_implementations)]
398 pub struct CastToUnit;
399
400 // SAFETY: The `project` implementation projects to a subset of its
401 // argument's referent using provenance-preserving operations.
402 unsafe impl<T: ?Sized> Project<T, ()> for CastToUnit {
403 #[inline(always)]
404 fn project(src: PtrInner<'_, T>) -> *mut () {
405 src.as_ptr().cast::<()>()
406 }
407 }
408
409 // SAFETY: The `project` implementation preserves referent address.
410 unsafe impl<T: ?Sized> Cast<T, ()> for CastToUnit {}
411}