xref: /linux/rust/zerocopy/src/pointer/inner.rs (revision c37398010a05055e78cf0c75defb90df06c4e999)
1 // Copyright 2024 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 use core::{marker::PhantomData, ops::Range, ptr::NonNull};
10 
11 pub use _def::PtrInner;
12 
13 #[allow(unused_imports)]
14 use crate::util::polyfills::NumExt as _;
15 use crate::{
16     layout::{CastType, MetadataCastError},
17     pointer::cast,
18     util::AsAddress,
19     AlignmentError, CastError, KnownLayout, MetadataOf, SizeError, SplitAt,
20 };
21 
22 mod _def {
23     use super::*;
24     /// The inner pointer stored inside a [`Ptr`][crate::Ptr].
25     ///
26     /// `PtrInner<'a, T>` is [covariant] in `'a` and invariant in `T`.
27     ///
28     /// [covariant]: https://doc.rust-lang.org/reference/subtyping.html
29     #[allow(missing_debug_implementations)]
30     pub struct PtrInner<'a, T>
31     where
32         T: ?Sized,
33     {
34         /// # Invariants
35         ///
36         /// 0. If `ptr`'s referent is not zero sized, then `ptr` has valid
37         ///    provenance for its referent, which is entirely contained in some
38         ///    Rust allocation, `A`.
39         /// 1. If `ptr`'s referent is not zero sized, `A` is guaranteed to live
40         ///    for at least `'a`.
41         ///
42         /// # Postconditions
43         ///
44         /// By virtue of these invariants, code may assume the following, which
45         /// are logical implications of the invariants:
46         /// - `ptr`'s referent is not larger than `isize::MAX` bytes \[1\]
47         /// - `ptr`'s referent does not wrap around the address space \[1\]
48         ///
49         /// \[1\] Per <https://doc.rust-lang.org/1.85.0/std/ptr/index.html#allocated-object>:
50         ///
51         ///   For any allocated object with `base` address, `size`, and a set of
52         ///   `addresses`, the following are guaranteed:
53         ///   ...
54         ///   - `size <= isize::MAX`
55         ///
56         ///   As a consequence of these guarantees, given any address `a` within
57         ///   the set of addresses of an allocated object:
58         ///   ...
59         ///   - It is guaranteed that, given `o = a - base` (i.e., the offset of
60         ///     `a` within the allocated object), `base + o` will not wrap
61         ///     around the address space (in other words, will not overflow
62         ///     `usize`)
63         ptr: NonNull<T>,
64         // SAFETY: `&'a UnsafeCell<T>` is covariant in `'a` and invariant in `T`
65         // [1]. We use this construction rather than the equivalent `&mut T`,
66         // because our MSRV of 1.65 prohibits `&mut` types in const contexts.
67         //
68         // [1] https://doc.rust-lang.org/1.81.0/reference/subtyping.html#variance
69         _marker: PhantomData<&'a core::cell::UnsafeCell<T>>,
70     }
71 
72     impl<'a, T: 'a + ?Sized> Copy for PtrInner<'a, T> {}
73     impl<'a, T: 'a + ?Sized> Clone for PtrInner<'a, T> {
74         #[inline(always)]
75         fn clone(&self) -> PtrInner<'a, T> {
76             // SAFETY: None of the invariants on `ptr` are affected by having
77             // multiple copies of a `PtrInner`.
78             *self
79         }
80     }
81 
82     impl<'a, T: 'a + ?Sized> PtrInner<'a, T> {
83         /// Constructs a `Ptr` from a [`NonNull`].
84         ///
85         /// # Safety
86         ///
87         /// The caller promises that:
88         ///
89         /// 0. If `ptr`'s referent is not zero sized, then `ptr` has valid
90         ///    provenance for its referent, which is entirely contained in some
91         ///    Rust allocation, `A`.
92         /// 1. If `ptr`'s referent is not zero sized, `A` is guaranteed to live
93         ///    for at least `'a`.
94         #[inline(always)]
95         #[must_use]
96         pub const unsafe fn new(ptr: NonNull<T>) -> PtrInner<'a, T> {
97             // SAFETY: The caller has promised to satisfy all safety invariants
98             // of `PtrInner`.
99             Self { ptr, _marker: PhantomData }
100         }
101 
102         /// Converts this `PtrInner<T>` to a [`NonNull<T>`].
103         ///
104         /// Note that this method does not consume `self`. The caller should
105         /// watch out for `unsafe` code which uses the returned `NonNull` in a
106         /// way that violates the safety invariants of `self`.
107         #[inline(always)]
108         #[must_use]
109         pub const fn as_non_null(&self) -> NonNull<T> {
110             self.ptr
111         }
112 
113         /// Converts this `PtrInner<T>` to a [`*mut T`].
114         ///
115         /// Note that this method does not consume `self`. The caller should
116         /// watch out for `unsafe` code which uses the returned `*mut T` in a
117         /// way that violates the safety invariants of `self`.
118         #[inline(always)]
119         #[must_use]
120         pub const fn as_ptr(&self) -> *mut T {
121             self.ptr.as_ptr()
122         }
123     }
124 }
125 
126 impl<'a, T: ?Sized> PtrInner<'a, T> {
127     /// Constructs a `PtrInner` from a reference.
128     #[inline]
129     pub fn from_ref(ptr: &'a T) -> Self {
130         let ptr = NonNull::from(ptr);
131         // SAFETY:
132         // 0. If `ptr`'s referent is not zero sized, then `ptr`, by invariant on
133         //    `&'a T` [1], has valid provenance for its referent, which is
134         //    entirely contained in some Rust allocation, `A`.
135         // 1. If `ptr`'s referent is not zero sized, then `A`, by invariant on
136         //    `&'a T`, is guaranteed to live for at least `'a`.
137         //
138         // [1] Per https://doc.rust-lang.org/1.85.0/std/primitive.reference.html#safety:
139         //
140         //   For all types, `T: ?Sized`, and for all `t: &T` or `t: &mut T`,
141         //   when such values cross an API boundary, the following invariants
142         //   must generally be upheld:
143         //   ...
144         //   - if `size_of_val(t) > 0`, then `t` is dereferenceable for
145         //     `size_of_val(t)` many bytes
146         //
147         //   If `t` points at address `a`, being “dereferenceable” for N bytes
148         //   means that the memory range `[a, a + N)` is all contained within a
149         //   single allocated object.
150         unsafe { Self::new(ptr) }
151     }
152 
153     /// Constructs a `PtrInner` from a mutable reference.
154     #[inline]
155     pub fn from_mut(ptr: &'a mut T) -> Self {
156         let ptr = NonNull::from(ptr);
157         // SAFETY:
158         // 0. If `ptr`'s referent is not zero sized, then `ptr`, by invariant on
159         //    `&'a mut T` [1], has valid provenance for its referent, which is
160         //    entirely contained in some Rust allocation, `A`.
161         // 1. If `ptr`'s referent is not zero sized, then `A`, by invariant on
162         //    `&'a mut T`, is guaranteed to live for at least `'a`.
163         //
164         // [1] Per https://doc.rust-lang.org/1.85.0/std/primitive.reference.html#safety:
165         //
166         //   For all types, `T: ?Sized`, and for all `t: &T` or `t: &mut T`,
167         //   when such values cross an API boundary, the following invariants
168         //   must generally be upheld:
169         //   ...
170         //   - if `size_of_val(t) > 0`, then `t` is dereferenceable for
171         //     `size_of_val(t)` many bytes
172         //
173         //   If `t` points at address `a`, being “dereferenceable” for N bytes
174         //   means that the memory range `[a, a + N)` is all contained within a
175         //   single allocated object.
176         unsafe { Self::new(ptr) }
177     }
178 
179     /// # Safety
180     ///
181     /// The caller may assume that the resulting `PtrInner` addresses the subset
182     /// of the bytes of `self`'s referent addressed by `C::project(self)`.
183     #[must_use]
184     #[inline(always)]
185     pub fn project<U: ?Sized, C: cast::Project<T, U>>(self) -> PtrInner<'a, U> {
186         let projected_raw = C::project(self);
187 
188         // SAFETY: `self`'s referent lives at a `NonNull` address, and is either
189         // zero-sized or lives in an allocation. In either case, it does not
190         // wrap around the address space [1], and so none of the addresses
191         // contained in it or one-past-the-end of it are null.
192         //
193         // By invariant on `C: Project`, `C::project` is a provenance-preserving
194         // projection which preserves or shrinks the set of referent bytes, so
195         // `projected_raw` references a subset of `self`'s referent, and so it
196         // cannot be null.
197         //
198         // [1] https://doc.rust-lang.org/1.92.0/std/ptr/index.html#allocation
199         let projected_non_null = unsafe { NonNull::new_unchecked(projected_raw) };
200 
201         // SAFETY: As described in the preceding safety comment, `projected_raw`,
202         // and thus `projected_non_null`, addresses a subset of `self`'s
203         // referent. Thus, `projected_non_null` either:
204         // - Addresses zero bytes or,
205         // - Addresses a subset of the referent of `self`. In this case, `self`
206         //   has provenance for its referent, which lives in an allocation.
207         //   Since `projected_non_null` was constructed using a sequence of
208         //   provenance-preserving operations, it also has provenance for its
209         //   referent and that referent lives in an allocation. By invariant on
210         //   `self`, that allocation lives for `'a`.
211         unsafe { PtrInner::new(projected_non_null) }
212     }
213 }
214 
215 #[allow(clippy::needless_lifetimes)]
216 impl<'a, T> PtrInner<'a, T>
217 where
218     T: ?Sized + KnownLayout,
219 {
220     /// Extracts the metadata of this `ptr`.
221     #[inline]
222     #[must_use]
223     pub fn meta(self) -> MetadataOf<T> {
224         let meta = T::pointer_to_metadata(self.as_ptr());
225         // SAFETY: By invariant on `PtrInner`, `self.as_non_null()` addresses no
226         // more than `isize::MAX` bytes.
227         unsafe { MetadataOf::new_unchecked(meta) }
228     }
229 
230     /// Produces a `PtrInner` with the same address and provenance as `self` but
231     /// the given `meta`.
232     ///
233     /// # Safety
234     ///
235     /// The caller promises that if `self`'s referent is not zero sized, then
236     /// a pointer constructed from its address with the given `meta` metadata
237     /// will address a subset of the allocation pointed to by `self`.
238     #[inline]
239     #[must_use]
240     pub unsafe fn with_meta(self, meta: T::PointerMetadata) -> Self
241     where
242         T: KnownLayout,
243     {
244         let raw = T::raw_from_ptr_len(self.as_non_null().cast(), meta);
245 
246         // SAFETY:
247         //
248         // Lemma 0: `raw` either addresses zero bytes, or addresses a subset of
249         //          the allocation pointed to by `self` and has the same
250         //          provenance as `self`. Proof: `raw` is constructed using
251         //          provenance-preserving operations, and the caller has
252         //          promised that, if `self`'s referent is not zero-sized, the
253         //          resulting pointer addresses a subset of the allocation
254         //          pointed to by `self`.
255         //
256         // 0. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not
257         //    zero sized, then `ptr` is derived from some valid Rust allocation,
258         //    `A`.
259         // 1. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not
260         //    zero sized, then `ptr` has valid provenance for `A`.
261         // 2. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not
262         //    zero sized, then `ptr` addresses a byte range which is entirely
263         //    contained in `A`.
264         // 3. Per Lemma 0 and by invariant on `self`, `ptr` addresses a byte
265         //    range whose length fits in an `isize`.
266         // 4. Per Lemma 0 and by invariant on `self`, `ptr` addresses a byte
267         //    range which does not wrap around the address space.
268         // 5. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not
269         //    zero sized, then `A` is guaranteed to live for at least `'a`.
270         unsafe { PtrInner::new(raw) }
271     }
272 }
273 
274 #[allow(clippy::needless_lifetimes)]
275 impl<'a, T> PtrInner<'a, T>
276 where
277     T: ?Sized + KnownLayout<PointerMetadata = usize>,
278 {
279     /// Splits `T` in two.
280     ///
281     /// # Safety
282     ///
283     /// The caller promises that:
284     ///  - `l_len.get() <= self.meta()`.
285     ///
286     /// ## (Non-)Overlap
287     ///
288     /// Given `let (left, right) = ptr.split_at(l_len)`, it is guaranteed that
289     /// `left` and `right` are contiguous and non-overlapping if
290     /// `l_len.padding_needed_for() == 0`. This is true for all `[T]`.
291     ///
292     /// If `l_len.padding_needed_for() != 0`, then the left pointer will overlap
293     /// the right pointer to satisfy `T`'s padding requirements.
294     #[inline]
295     #[must_use]
296     pub unsafe fn split_at_unchecked(
297         self,
298         l_len: crate::util::MetadataOf<T>,
299     ) -> (Self, PtrInner<'a, [T::Elem]>)
300     where
301         T: SplitAt,
302     {
303         let l_len = l_len.get();
304 
305         // SAFETY: The caller promises that `l_len.get() <= self.meta()`.
306         // Trivially, `0 <= l_len`.
307         let left = unsafe { self.with_meta(l_len) };
308 
309         let right = self.trailing_slice();
310         // SAFETY: The caller promises that `l_len <= self.meta() = slf.meta()`.
311         // Trivially, `slf.meta() <= slf.meta()`.
312         let right = unsafe { right.slice_unchecked(l_len..self.meta().get()) };
313 
314         // SAFETY: If `l_len.padding_needed_for() == 0`, then `left` and `right`
315         // are non-overlapping. Proof: `left` is constructed `slf` with `l_len`
316         // as its (exclusive) upper bound. If `l_len.padding_needed_for() == 0`,
317         // then `left` requires no trailing padding following its final element.
318         // Since `right` is constructed from `slf`'s trailing slice with `l_len`
319         // as its (inclusive) lower bound, no byte is referred to by both
320         // pointers.
321         //
322         // Conversely, `l_len.padding_needed_for() == N`, where `N
323         // > 0`, `left` requires `N` bytes of trailing padding following its
324         // final element. Since `right` is constructed from the trailing slice
325         // of `slf` with `l_len` as its (inclusive) lower bound, the first `N`
326         // bytes of `right` are aliased by `left`.
327         (left, right)
328     }
329 
330     /// Produces the trailing slice of `self`.
331     #[inline]
332     #[must_use]
333     pub fn trailing_slice(self) -> PtrInner<'a, [T::Elem]>
334     where
335         T: SplitAt,
336     {
337         let offset = crate::trailing_slice_layout::<T>().offset;
338 
339         let bytes = self.as_non_null().cast::<u8>().as_ptr();
340 
341         // SAFETY:
342         // - By invariant on `T: KnownLayout`, `T::LAYOUT` describes `T`'s
343         //   layout. `offset` is the offset of the trailing slice within `T`,
344         //   which is by definition in-bounds or one byte past the end of any
345         //   `T`, regardless of metadata. By invariant on `PtrInner`, `self`
346         //   (and thus `bytes`) points to a byte range of size `<= isize::MAX`,
347         //   and so `offset <= isize::MAX`. Since `size_of::<u8>() == 1`,
348         //   `offset * size_of::<u8>() <= isize::MAX`.
349         // - If `offset > 0`, then by invariant on `PtrInner`, `self` (and thus
350         //   `bytes`) points to a byte range entirely contained within the same
351         //   allocated object as `self`. As explained above, this offset results
352         //   in a pointer to or one byte past the end of this allocated object.
353         let bytes = unsafe { bytes.add(offset) };
354 
355         // SAFETY: By the preceding safety argument, `bytes` is within or one
356         // byte past the end of the same allocated object as `self`, which
357         // ensures that it is non-null.
358         let bytes = unsafe { NonNull::new_unchecked(bytes) };
359 
360         let ptr = KnownLayout::raw_from_ptr_len(bytes, self.meta().get());
361 
362         // SAFETY:
363         // 0. If `ptr`'s referent is not zero sized, then `ptr` is derived from
364         //    some valid Rust allocation, `A`, because `ptr` is derived from
365         //    the same allocated object as `self`.
366         // 1. If `ptr`'s referent is not zero sized, then `ptr` has valid
367         //    provenance for `A` because `raw` is derived from the same
368         //    allocated object as `self` via provenance-preserving operations.
369         // 2. If `ptr`'s referent is not zero sized, then `ptr` addresses a byte
370         //    range which is entirely contained in `A`, by previous safety proof
371         //    on `bytes`.
372         // 3. `ptr` addresses a byte range whose length fits in an `isize`, by
373         //    consequence of #2.
374         // 4. `ptr` addresses a byte range which does not wrap around the
375         //    address space, by consequence of #2.
376         // 5. If `ptr`'s referent is not zero sized, then `A` is guaranteed to
377         //    live for at least `'a`, because `ptr` is derived from `self`.
378         unsafe { PtrInner::new(ptr) }
379     }
380 }
381 
382 #[allow(clippy::needless_lifetimes)]
383 impl<'a, T> PtrInner<'a, [T]> {
384     /// Creates a pointer which addresses the given `range` of self.
385     ///
386     /// # Safety
387     ///
388     /// `range` is a valid range (`start <= end`) and `end <= self.meta()`.
389     #[inline]
390     #[must_use]
391     pub unsafe fn slice_unchecked(self, range: Range<usize>) -> Self {
392         let base = self.as_non_null().cast::<T>().as_ptr();
393 
394         // SAFETY: The caller promises that `start <= end <= self.meta()`. By
395         // invariant, if `self`'s referent is not zero-sized, then `self` refers
396         // to a byte range which is contained within a single allocation, which
397         // is no more than `isize::MAX` bytes long, and which does not wrap
398         // around the address space. Thus, this pointer arithmetic remains
399         // in-bounds of the same allocation, and does not wrap around the
400         // address space. The offset (in bytes) does not overflow `isize`.
401         //
402         // If `self`'s referent is zero-sized, then these conditions are
403         // trivially satisfied.
404         let base = unsafe { base.add(range.start) };
405 
406         // SAFETY: The caller promises that `start <= end`, and so this will not
407         // underflow.
408         #[allow(unstable_name_collisions)]
409         let len = unsafe { range.end.unchecked_sub(range.start) };
410 
411         let ptr = core::ptr::slice_from_raw_parts_mut(base, len);
412 
413         // SAFETY: By invariant, `self`'s referent is either a ZST or lives
414         // entirely in an allocation. `ptr` points inside of or one byte past
415         // the end of that referent. Thus, in either case, `ptr` is non-null.
416         let ptr = unsafe { NonNull::new_unchecked(ptr) };
417 
418         // SAFETY:
419         //
420         // Lemma 0: `ptr` addresses a subset of the bytes addressed by `self`,
421         //          and has the same provenance. Proof: The caller guarantees
422         //          that `start <= end <= self.meta()`. Thus, `base` is
423         //          in-bounds of `self`, and `base + (end - start)` is also
424         //          in-bounds of self. Finally, `ptr` is constructed using
425         //          provenance-preserving operations.
426         //
427         // 0. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not
428         //    zero sized, then `ptr` has valid provenance for its referent,
429         //    which is entirely contained in some Rust allocation, `A`.
430         // 1. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not
431         //    zero sized, then `A` is guaranteed to live for at least `'a`.
432         unsafe { PtrInner::new(ptr) }
433     }
434 
435     /// Iteratively projects the elements `PtrInner<T>` from `PtrInner<[T]>`.
436     #[inline]
437     pub fn iter(&self) -> impl Iterator<Item = PtrInner<'a, T>> {
438         // FIXME(#429): Once `NonNull::cast` documents that it preserves
439         // provenance, cite those docs.
440         let base = self.as_non_null().cast::<T>().as_ptr();
441         (0..self.meta().get()).map(move |i| {
442             // FIXME(https://github.com/rust-lang/rust/issues/74265): Use
443             // `NonNull::get_unchecked_mut`.
444 
445             // SAFETY: If the following conditions are not satisfied
446             // `pointer::cast` may induce Undefined Behavior [1]:
447             //
448             // > - The computed offset, `count * size_of::<T>()` bytes, must not
449             // >   overflow `isize``.
450             // > - If the computed offset is non-zero, then `self` must be
451             // >   derived from a pointer to some allocated object, and the
452             // >   entire memory range between `self` and the result must be in
453             // >   bounds of that allocated object. In particular, this range
454             // >   must not “wrap around” the edge of the address space.
455             //
456             // [1] https://doc.rust-lang.org/std/primitive.pointer.html#method.add
457             //
458             // We satisfy both of these conditions here:
459             // - By invariant on `Ptr`, `self` addresses a byte range whose
460             //   length fits in an `isize`. Since `elem` is contained in `self`,
461             //   the computed offset of `elem` must fit within `isize.`
462             // - If the computed offset is non-zero, then this means that the
463             //   referent is not zero-sized. In this case, `base` points to an
464             //   allocated object (by invariant on `self`). Thus:
465             //   - By contract, `self.meta()` accurately reflects the number of
466             //     elements in the slice. `i` is in bounds of `c.meta()` by
467             //     construction, and so the result of this addition cannot
468             //     overflow past the end of the allocation referred to by `c`.
469             //   - By invariant on `Ptr`, `self` addresses a byte range which
470             //     does not wrap around the address space. Since `elem` is
471             //     contained in `self`, the computed offset of `elem` must wrap
472             //     around the address space.
473             //
474             // FIXME(#429): Once `pointer::add` documents that it preserves
475             // provenance, cite those docs.
476             let elem = unsafe { base.add(i) };
477 
478             // SAFETY: `elem` must not be null. `base` is constructed from a
479             // `NonNull` pointer, and the addition that produces `elem` must not
480             // overflow or wrap around, so `elem >= base > 0`.
481             //
482             // FIXME(#429): Once `NonNull::new_unchecked` documents that it
483             // preserves provenance, cite those docs.
484             let elem = unsafe { NonNull::new_unchecked(elem) };
485 
486             // SAFETY: The safety invariants of `Ptr::new` (see definition) are
487             // satisfied:
488             // 0. If `elem`'s referent is not zero sized, then `elem` has valid
489             //    provenance for its referent, because it derived from `self`
490             //    using a series of provenance-preserving operations, and
491             //    because `self` has valid provenance for its referent. By the
492             //    same argument, `elem`'s referent is entirely contained within
493             //    the same allocated object as `self`'s referent.
494             // 1. If `elem`'s referent is not zero sized, then the allocation of
495             //    `elem` is guaranteed to live for at least `'a`, because `elem`
496             //    is entirely contained in `self`, which lives for at least `'a`
497             //    by invariant on `Ptr`.
498             unsafe { PtrInner::new(elem) }
499         })
500     }
501 }
502 
503 impl<'a, T, const N: usize> PtrInner<'a, [T; N]> {
504     /// Casts this pointer-to-array into a slice.
505     ///
506     /// # Safety
507     ///
508     /// Callers may assume that the returned `PtrInner` references the same
509     /// address and length as `self`.
510     #[allow(clippy::wrong_self_convention)]
511     #[inline]
512     #[must_use]
513     pub fn as_slice(self) -> PtrInner<'a, [T]> {
514         let start = self.as_non_null().cast::<T>().as_ptr();
515         let slice = core::ptr::slice_from_raw_parts_mut(start, N);
516         // SAFETY: `slice` is not null, because it is derived from `start`
517         // which is non-null.
518         let slice = unsafe { NonNull::new_unchecked(slice) };
519         // SAFETY: Lemma: In the following safety arguments, note that `slice`
520         // is derived from `self` in two steps: first, by casting `self: [T; N]`
521         // to `start: T`, then by constructing a pointer to a slice starting at
522         // `start` of length `N`. As a result, `slice` references exactly the
523         // same allocation as `self`, if any.
524         //
525         // 0. By the above lemma, if `slice`'s referent is not zero sized, then
526         //    `slice` has the same referent as `self`. By invariant on `self`,
527         //    this referent is entirely contained within some allocation, `A`.
528         //    Because `slice` was constructed using provenance-preserving
529         //    operations, it has provenance for its entire referent.
530         // 1. By the above lemma, if `slice`'s referent is not zero sized, then
531         //    `A` is guaranteed to live for at least `'a`, because it is derived
532         //    from the same allocation as `self`, which, by invariant on
533         //    `PtrInner`, lives for at least `'a`.
534         unsafe { PtrInner::new(slice) }
535     }
536 }
537 
538 impl<'a> PtrInner<'a, [u8]> {
539     /// Attempts to cast `self` to a `U` using the given cast type.
540     ///
541     /// If `U` is a slice DST and pointer metadata (`meta`) is provided, then
542     /// the cast will only succeed if it would produce an object with the given
543     /// metadata.
544     ///
545     /// Returns `None` if the resulting `U` would be invalidly-aligned, if no
546     /// `U` can fit in `self`, or if the provided pointer metadata describes an
547     /// invalid instance of `U`. On success, returns a pointer to the
548     /// largest-possible `U` which fits in `self`.
549     ///
550     /// # Safety
551     ///
552     /// The caller may assume that this implementation is correct, and may rely
553     /// on that assumption for the soundness of their code. In particular, the
554     /// caller may assume that, if `try_cast_into` returns `Some((ptr,
555     /// remainder))`, then `ptr` and `remainder` refer to non-overlapping byte
556     /// ranges within `self`, and that `ptr` and `remainder` entirely cover
557     /// `self`. Finally:
558     /// - If this is a prefix cast, `ptr` has the same address as `self`.
559     /// - If this is a suffix cast, `remainder` has the same address as `self`.
560     #[inline]
561     pub fn try_cast_into<U>(
562         self,
563         cast_type: CastType,
564         meta: Option<U::PointerMetadata>,
565     ) -> Result<(PtrInner<'a, U>, PtrInner<'a, [u8]>), CastError<Self, U>>
566     where
567         U: 'a + ?Sized + KnownLayout,
568     {
569         // PANICS: By invariant, the byte range addressed by
570         // `self.as_non_null()` does not wrap around the address space. This
571         // implies that the sum of the address (represented as a `usize`) and
572         // length do not overflow `usize`, as required by
573         // `validate_cast_and_convert_metadata`. Thus, this call to
574         // `validate_cast_and_convert_metadata` will only panic if `U` is a DST
575         // whose trailing slice element is zero-sized.
576         let maybe_metadata = MetadataOf::<U>::validate_cast_and_convert_metadata(
577             AsAddress::addr(self.as_ptr()),
578             self.meta(),
579             cast_type,
580             meta,
581         );
582 
583         let (elems, split_at) = match maybe_metadata {
584             Ok((elems, split_at)) => (elems, split_at),
585             Err(MetadataCastError::Alignment) => {
586                 // SAFETY: Since `validate_cast_and_convert_metadata` returned
587                 // an alignment error, `U` must have an alignment requirement
588                 // greater than one.
589                 let err = unsafe { AlignmentError::<_, U>::new_unchecked(self) };
590                 return Err(CastError::Alignment(err));
591             }
592             Err(MetadataCastError::Size) => return Err(CastError::Size(SizeError::new(self))),
593         };
594 
595         // SAFETY: `validate_cast_and_convert_metadata` promises to return
596         // `split_at <= self.meta()`.
597         //
598         // Lemma 0: `l_slice` and `r_slice` are non-overlapping. Proof: By
599         // contract on `PtrInner::split_at_unchecked`, the produced `PtrInner`s
600         // are always non-overlapping if `self` is a `[T]`; here it is a `[u8]`.
601         let (l_slice, r_slice) = unsafe { self.split_at_unchecked(split_at) };
602 
603         let (target, remainder) = match cast_type {
604             CastType::Prefix => (l_slice, r_slice),
605             CastType::Suffix => (r_slice, l_slice),
606         };
607 
608         let base = target.as_non_null().cast::<u8>();
609 
610         let ptr = U::raw_from_ptr_len(base, elems.get());
611 
612         // SAFETY:
613         // 0. By invariant, if `target`'s referent is not zero sized, then
614         //    `target` has provenance valid for some Rust allocation, `A`.
615         //    Because `ptr` is derived from `target` via provenance-preserving
616         //    operations, `ptr` will also have provenance valid for its entire
617         //    referent.
618         // 1. `validate_cast_and_convert_metadata` promises that the object
619         //    described by `elems` and `split_at` lives at a byte range which is
620         //    a subset of the input byte range. Thus, by invariant, if
621         //    `target`'s referent is not zero sized, then `target` refers to an
622         //    allocation which is guaranteed to live for at least `'a`, and thus
623         //    so does `ptr`.
624         Ok((unsafe { PtrInner::new(ptr) }, remainder))
625     }
626 }
627 
628 #[cfg(test)]
629 mod tests {
630     use super::*;
631     use crate::*;
632 
633     #[test]
634     fn test_meta() {
635         let arr = [1; 16];
636         let dst = <[u8]>::ref_from_bytes(&arr[..]).unwrap();
637         let ptr = PtrInner::from_ref(dst);
638         assert_eq!(ptr.meta().get(), 16);
639 
640         // SAFETY: 8 is less than 16
641         let ptr = unsafe { ptr.with_meta(8) };
642 
643         assert_eq!(ptr.meta().get(), 8);
644     }
645 
646     #[test]
647     fn test_split_at() {
648         fn test_split_at<const OFFSET: usize, const BUFFER_SIZE: usize>() {
649             #[derive(FromBytes, KnownLayout, SplitAt, Immutable)]
650             #[repr(C)]
651             struct SliceDst<const OFFSET: usize> {
652                 prefix: [u8; OFFSET],
653                 trailing: [u8],
654             }
655 
656             let n: usize = BUFFER_SIZE - OFFSET;
657             let arr = [1; BUFFER_SIZE];
658             let dst = SliceDst::<OFFSET>::ref_from_bytes(&arr[..]).unwrap();
659             let ptr = PtrInner::from_ref(dst);
660             for i in 0..=n {
661                 assert_eq!(ptr.meta().get(), n);
662                 // SAFETY: `i` is in bounds by construction.
663                 let i = unsafe { MetadataOf::new_unchecked(i) };
664                 // SAFETY: `i` is in bounds by construction.
665                 let (l, r) = unsafe { ptr.split_at_unchecked(i) };
666                 // SAFETY: Points to a valid value by construction.
667                 #[allow(clippy::undocumented_unsafe_blocks, clippy::as_conversions)]
668                 // Clippy false positive
669                 let l_sum: usize = l
670                     .trailing_slice()
671                     .iter()
672                     .map(
673                         #[inline(always)]
674                         |ptr| unsafe { core::ptr::read_unaligned(ptr.as_ptr()) } as usize,
675                     )
676                     .sum();
677                 // SAFETY: Points to a valid value by construction.
678                 #[allow(clippy::undocumented_unsafe_blocks, clippy::as_conversions)]
679                 // Clippy false positive
680                 let r_sum: usize = r
681                     .iter()
682                     .map(
683                         #[inline(always)]
684                         |ptr| unsafe { core::ptr::read_unaligned(ptr.as_ptr()) } as usize,
685                     )
686                     .sum();
687                 assert_eq!(l_sum, i.get());
688                 assert_eq!(r_sum, n - i.get());
689                 assert_eq!(l_sum + r_sum, n);
690             }
691         }
692 
693         test_split_at::<0, 16>();
694         test_split_at::<1, 17>();
695         test_split_at::<2, 18>();
696     }
697 
698     #[test]
699     fn test_trailing_slice() {
700         fn test_trailing_slice<const OFFSET: usize, const BUFFER_SIZE: usize>() {
701             #[derive(FromBytes, KnownLayout, SplitAt, Immutable)]
702             #[repr(C)]
703             struct SliceDst<const OFFSET: usize> {
704                 prefix: [u8; OFFSET],
705                 trailing: [u8],
706             }
707 
708             let n: usize = BUFFER_SIZE - OFFSET;
709             let arr = [1; BUFFER_SIZE];
710             let dst = SliceDst::<OFFSET>::ref_from_bytes(&arr[..]).unwrap();
711             let ptr = PtrInner::from_ref(dst);
712 
713             assert_eq!(ptr.meta().get(), n);
714             let trailing = ptr.trailing_slice();
715             assert_eq!(trailing.meta().get(), n);
716 
717             assert_eq!(
718                 // SAFETY: We assume this to be sound for the sake of this test,
719                 // which will fail, here, in miri, if the safety precondition of
720                 // `offset_of` is not satisfied.
721                 unsafe {
722                     #[allow(clippy::as_conversions)]
723                     let offset = (trailing.as_ptr() as *mut u8).offset_from(ptr.as_ptr() as *mut _);
724                     offset
725                 },
726                 isize::try_from(OFFSET).unwrap(),
727             );
728 
729             // SAFETY: Points to a valid value by construction.
730             #[allow(clippy::undocumented_unsafe_blocks, clippy::as_conversions)]
731             // Clippy false positive
732             let trailing: usize = trailing
733                 .iter()
734                 .map(|ptr| unsafe { core::ptr::read_unaligned(ptr.as_ptr()) } as usize)
735                 .sum();
736 
737             assert_eq!(trailing, n);
738         }
739 
740         test_trailing_slice::<0, 16>();
741         test_trailing_slice::<1, 17>();
742         test_trailing_slice::<2, 18>();
743     }
744     #[test]
745     fn test_ptr_inner_clone() {
746         let mut x = 0u8;
747         let p = PtrInner::from_mut(&mut x);
748         #[allow(clippy::clone_on_copy)]
749         let p2 = p.clone();
750         assert_eq!(p.as_non_null(), p2.as_non_null());
751     }
752 }
753