zerocopy/pointer/inner.rs
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
9use core::{marker::PhantomData, ops::Range, ptr::NonNull};
10
11pub use _def::PtrInner;
12
13#[allow(unused_imports)]
14use crate::util::polyfills::NumExt as _;
15use crate::{
16 layout::{CastType, MetadataCastError},
17 pointer::cast,
18 util::AsAddress,
19 AlignmentError, CastError, KnownLayout, MetadataOf, SizeError, SplitAt,
20};
21
22mod _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
126impl<'a, T: ?Sized> PtrInner<'a, T> {
127 /// Constructs a `PtrInner` from a reference.
128 #[inline]
129 pub(crate) 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(crate) 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 a subset
182 /// of the bytes of `self`'s referent.
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)]
216impl<'a, T> PtrInner<'a, T>
217where
218 T: ?Sized + KnownLayout,
219{
220 /// Extracts the metadata of this `ptr`.
221 pub(crate) fn meta(self) -> MetadataOf<T> {
222 let meta = T::pointer_to_metadata(self.as_ptr());
223 // SAFETY: By invariant on `PtrInner`, `self.as_non_null()` addresses no
224 // more than `isize::MAX` bytes.
225 unsafe { MetadataOf::new_unchecked(meta) }
226 }
227
228 /// Produces a `PtrInner` with the same address and provenance as `self` but
229 /// the given `meta`.
230 ///
231 /// # Safety
232 ///
233 /// The caller promises that if `self`'s referent is not zero sized, then
234 /// a pointer constructed from its address with the given `meta` metadata
235 /// will address a subset of the allocation pointed to by `self`.
236 #[inline]
237 pub(crate) unsafe fn with_meta(self, meta: T::PointerMetadata) -> Self
238 where
239 T: KnownLayout,
240 {
241 let raw = T::raw_from_ptr_len(self.as_non_null().cast(), meta);
242
243 // SAFETY:
244 //
245 // Lemma 0: `raw` either addresses zero bytes, or addresses a subset of
246 // the allocation pointed to by `self` and has the same
247 // provenance as `self`. Proof: `raw` is constructed using
248 // provenance-preserving operations, and the caller has
249 // promised that, if `self`'s referent is not zero-sized, the
250 // resulting pointer addresses a subset of the allocation
251 // pointed to by `self`.
252 //
253 // 0. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not
254 // zero sized, then `ptr` is derived from some valid Rust allocation,
255 // `A`.
256 // 1. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not
257 // zero sized, then `ptr` has valid provenance for `A`.
258 // 2. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not
259 // zero sized, then `ptr` addresses a byte range which is entirely
260 // contained in `A`.
261 // 3. Per Lemma 0 and by invariant on `self`, `ptr` addresses a byte
262 // range whose length fits in an `isize`.
263 // 4. Per Lemma 0 and by invariant on `self`, `ptr` addresses a byte
264 // range which does not wrap around the address space.
265 // 5. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not
266 // zero sized, then `A` is guaranteed to live for at least `'a`.
267 unsafe { PtrInner::new(raw) }
268 }
269}
270
271#[allow(clippy::needless_lifetimes)]
272impl<'a, T> PtrInner<'a, T>
273where
274 T: ?Sized + KnownLayout<PointerMetadata = usize>,
275{
276 /// Splits `T` in two.
277 ///
278 /// # Safety
279 ///
280 /// The caller promises that:
281 /// - `l_len.get() <= self.meta()`.
282 ///
283 /// ## (Non-)Overlap
284 ///
285 /// Given `let (left, right) = ptr.split_at(l_len)`, it is guaranteed that
286 /// `left` and `right` are contiguous and non-overlapping if
287 /// `l_len.padding_needed_for() == 0`. This is true for all `[T]`.
288 ///
289 /// If `l_len.padding_needed_for() != 0`, then the left pointer will overlap
290 /// the right pointer to satisfy `T`'s padding requirements.
291 pub(crate) unsafe fn split_at_unchecked(
292 self,
293 l_len: crate::util::MetadataOf<T>,
294 ) -> (Self, PtrInner<'a, [T::Elem]>)
295 where
296 T: SplitAt,
297 {
298 let l_len = l_len.get();
299
300 // SAFETY: The caller promises that `l_len.get() <= self.meta()`.
301 // Trivially, `0 <= l_len`.
302 let left = unsafe { self.with_meta(l_len) };
303
304 let right = self.trailing_slice();
305 // SAFETY: The caller promises that `l_len <= self.meta() = slf.meta()`.
306 // Trivially, `slf.meta() <= slf.meta()`.
307 let right = unsafe { right.slice_unchecked(l_len..self.meta().get()) };
308
309 // SAFETY: If `l_len.padding_needed_for() == 0`, then `left` and `right`
310 // are non-overlapping. Proof: `left` is constructed `slf` with `l_len`
311 // as its (exclusive) upper bound. If `l_len.padding_needed_for() == 0`,
312 // then `left` requires no trailing padding following its final element.
313 // Since `right` is constructed from `slf`'s trailing slice with `l_len`
314 // as its (inclusive) lower bound, no byte is referred to by both
315 // pointers.
316 //
317 // Conversely, `l_len.padding_needed_for() == N`, where `N
318 // > 0`, `left` requires `N` bytes of trailing padding following its
319 // final element. Since `right` is constructed from the trailing slice
320 // of `slf` with `l_len` as its (inclusive) lower bound, the first `N`
321 // bytes of `right` are aliased by `left`.
322 (left, right)
323 }
324
325 /// Produces the trailing slice of `self`.
326 pub(crate) fn trailing_slice(self) -> PtrInner<'a, [T::Elem]>
327 where
328 T: SplitAt,
329 {
330 let offset = crate::trailing_slice_layout::<T>().offset;
331
332 let bytes = self.as_non_null().cast::<u8>().as_ptr();
333
334 // SAFETY:
335 // - By invariant on `T: KnownLayout`, `T::LAYOUT` describes `T`'s
336 // layout. `offset` is the offset of the trailing slice within `T`,
337 // which is by definition in-bounds or one byte past the end of any
338 // `T`, regardless of metadata. By invariant on `PtrInner`, `self`
339 // (and thus `bytes`) points to a byte range of size `<= isize::MAX`,
340 // and so `offset <= isize::MAX`. Since `size_of::<u8>() == 1`,
341 // `offset * size_of::<u8>() <= isize::MAX`.
342 // - If `offset > 0`, then by invariant on `PtrInner`, `self` (and thus
343 // `bytes`) points to a byte range entirely contained within the same
344 // allocated object as `self`. As explained above, this offset results
345 // in a pointer to or one byte past the end of this allocated object.
346 let bytes = unsafe { bytes.add(offset) };
347
348 // SAFETY: By the preceding safety argument, `bytes` is within or one
349 // byte past the end of the same allocated object as `self`, which
350 // ensures that it is non-null.
351 let bytes = unsafe { NonNull::new_unchecked(bytes) };
352
353 let ptr = KnownLayout::raw_from_ptr_len(bytes, self.meta().get());
354
355 // SAFETY:
356 // 0. If `ptr`'s referent is not zero sized, then `ptr` is derived from
357 // some valid Rust allocation, `A`, because `ptr` is derived from
358 // the same allocated object as `self`.
359 // 1. If `ptr`'s referent is not zero sized, then `ptr` has valid
360 // provenance for `A` because `raw` is derived from the same
361 // allocated object as `self` via provenance-preserving operations.
362 // 2. If `ptr`'s referent is not zero sized, then `ptr` addresses a byte
363 // range which is entirely contained in `A`, by previous safety proof
364 // on `bytes`.
365 // 3. `ptr` addresses a byte range whose length fits in an `isize`, by
366 // consequence of #2.
367 // 4. `ptr` addresses a byte range which does not wrap around the
368 // address space, by consequence of #2.
369 // 5. If `ptr`'s referent is not zero sized, then `A` is guaranteed to
370 // live for at least `'a`, because `ptr` is derived from `self`.
371 unsafe { PtrInner::new(ptr) }
372 }
373}
374
375#[allow(clippy::needless_lifetimes)]
376impl<'a, T> PtrInner<'a, [T]> {
377 /// Creates a pointer which addresses the given `range` of self.
378 ///
379 /// # Safety
380 ///
381 /// `range` is a valid range (`start <= end`) and `end <= self.meta()`.
382 pub(crate) unsafe fn slice_unchecked(self, range: Range<usize>) -> Self {
383 let base = self.as_non_null().cast::<T>().as_ptr();
384
385 // SAFETY: The caller promises that `start <= end <= self.meta()`. By
386 // invariant, if `self`'s referent is not zero-sized, then `self` refers
387 // to a byte range which is contained within a single allocation, which
388 // is no more than `isize::MAX` bytes long, and which does not wrap
389 // around the address space. Thus, this pointer arithmetic remains
390 // in-bounds of the same allocation, and does not wrap around the
391 // address space. The offset (in bytes) does not overflow `isize`.
392 //
393 // If `self`'s referent is zero-sized, then these conditions are
394 // trivially satisfied.
395 let base = unsafe { base.add(range.start) };
396
397 // SAFETY: The caller promises that `start <= end`, and so this will not
398 // underflow.
399 #[allow(unstable_name_collisions)]
400 let len = unsafe { range.end.unchecked_sub(range.start) };
401
402 let ptr = core::ptr::slice_from_raw_parts_mut(base, len);
403
404 // SAFETY: By invariant, `self`'s referent is either a ZST or lives
405 // entirely in an allocation. `ptr` points inside of or one byte past
406 // the end of that referent. Thus, in either case, `ptr` is non-null.
407 let ptr = unsafe { NonNull::new_unchecked(ptr) };
408
409 // SAFETY:
410 //
411 // Lemma 0: `ptr` addresses a subset of the bytes addressed by `self`,
412 // and has the same provenance. Proof: The caller guarantees
413 // that `start <= end <= self.meta()`. Thus, `base` is
414 // in-bounds of `self`, and `base + (end - start)` is also
415 // in-bounds of self. Finally, `ptr` is constructed using
416 // provenance-preserving operations.
417 //
418 // 0. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not
419 // zero sized, then `ptr` has valid provenance for its referent,
420 // which is entirely contained in some Rust allocation, `A`.
421 // 1. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not
422 // zero sized, then `A` is guaranteed to live for at least `'a`.
423 unsafe { PtrInner::new(ptr) }
424 }
425
426 /// Iteratively projects the elements `PtrInner<T>` from `PtrInner<[T]>`.
427 pub(crate) fn iter(&self) -> impl Iterator<Item = PtrInner<'a, T>> {
428 // FIXME(#429): Once `NonNull::cast` documents that it preserves
429 // provenance, cite those docs.
430 let base = self.as_non_null().cast::<T>().as_ptr();
431 (0..self.meta().get()).map(move |i| {
432 // FIXME(https://github.com/rust-lang/rust/issues/74265): Use
433 // `NonNull::get_unchecked_mut`.
434
435 // SAFETY: If the following conditions are not satisfied
436 // `pointer::cast` may induce Undefined Behavior [1]:
437 //
438 // > - The computed offset, `count * size_of::<T>()` bytes, must not
439 // > overflow `isize``.
440 // > - If the computed offset is non-zero, then `self` must be
441 // > derived from a pointer to some allocated object, and the
442 // > entire memory range between `self` and the result must be in
443 // > bounds of that allocated object. In particular, this range
444 // > must not “wrap around” the edge of the address space.
445 //
446 // [1] https://doc.rust-lang.org/std/primitive.pointer.html#method.add
447 //
448 // We satisfy both of these conditions here:
449 // - By invariant on `Ptr`, `self` addresses a byte range whose
450 // length fits in an `isize`. Since `elem` is contained in `self`,
451 // the computed offset of `elem` must fit within `isize.`
452 // - If the computed offset is non-zero, then this means that the
453 // referent is not zero-sized. In this case, `base` points to an
454 // allocated object (by invariant on `self`). Thus:
455 // - By contract, `self.meta()` accurately reflects the number of
456 // elements in the slice. `i` is in bounds of `c.meta()` by
457 // construction, and so the result of this addition cannot
458 // overflow past the end of the allocation referred to by `c`.
459 // - By invariant on `Ptr`, `self` addresses a byte range which
460 // does not wrap around the address space. Since `elem` is
461 // contained in `self`, the computed offset of `elem` must wrap
462 // around the address space.
463 //
464 // FIXME(#429): Once `pointer::add` documents that it preserves
465 // provenance, cite those docs.
466 let elem = unsafe { base.add(i) };
467
468 // SAFETY: `elem` must not be null. `base` is constructed from a
469 // `NonNull` pointer, and the addition that produces `elem` must not
470 // overflow or wrap around, so `elem >= base > 0`.
471 //
472 // FIXME(#429): Once `NonNull::new_unchecked` documents that it
473 // preserves provenance, cite those docs.
474 let elem = unsafe { NonNull::new_unchecked(elem) };
475
476 // SAFETY: The safety invariants of `Ptr::new` (see definition) are
477 // satisfied:
478 // 0. If `elem`'s referent is not zero sized, then `elem` has valid
479 // provenance for its referent, because it derived from `self`
480 // using a series of provenance-preserving operations, and
481 // because `self` has valid provenance for its referent. By the
482 // same argument, `elem`'s referent is entirely contained within
483 // the same allocated object as `self`'s referent.
484 // 1. If `elem`'s referent is not zero sized, then the allocation of
485 // `elem` is guaranteed to live for at least `'a`, because `elem`
486 // is entirely contained in `self`, which lives for at least `'a`
487 // by invariant on `Ptr`.
488 unsafe { PtrInner::new(elem) }
489 })
490 }
491}
492
493impl<'a, T, const N: usize> PtrInner<'a, [T; N]> {
494 /// Casts this pointer-to-array into a slice.
495 ///
496 /// # Safety
497 ///
498 /// Callers may assume that the returned `PtrInner` references the same
499 /// address and length as `self`.
500 #[allow(clippy::wrong_self_convention)]
501 pub(crate) fn as_slice(self) -> PtrInner<'a, [T]> {
502 let start = self.as_non_null().cast::<T>().as_ptr();
503 let slice = core::ptr::slice_from_raw_parts_mut(start, N);
504 // SAFETY: `slice` is not null, because it is derived from `start`
505 // which is non-null.
506 let slice = unsafe { NonNull::new_unchecked(slice) };
507 // SAFETY: Lemma: In the following safety arguments, note that `slice`
508 // is derived from `self` in two steps: first, by casting `self: [T; N]`
509 // to `start: T`, then by constructing a pointer to a slice starting at
510 // `start` of length `N`. As a result, `slice` references exactly the
511 // same allocation as `self`, if any.
512 //
513 // 0. By the above lemma, if `slice`'s referent is not zero sized, then
514 // `slice` has the same referent as `self`. By invariant on `self`,
515 // this referent is entirely contained within some allocation, `A`.
516 // Because `slice` was constructed using provenance-preserving
517 // operations, it has provenance for its entire referent.
518 // 1. By the above lemma, if `slice`'s referent is not zero sized, then
519 // `A` is guaranteed to live for at least `'a`, because it is derived
520 // from the same allocation as `self`, which, by invariant on `Ptr`,
521 // lives for at least `'a`.
522 unsafe { PtrInner::new(slice) }
523 }
524}
525
526impl<'a> PtrInner<'a, [u8]> {
527 /// Attempts to cast `self` to a `U` using the given cast type.
528 ///
529 /// If `U` is a slice DST and pointer metadata (`meta`) is provided, then
530 /// the cast will only succeed if it would produce an object with the given
531 /// metadata.
532 ///
533 /// Returns `None` if the resulting `U` would be invalidly-aligned, if no
534 /// `U` can fit in `self`, or if the provided pointer metadata describes an
535 /// invalid instance of `U`. On success, returns a pointer to the
536 /// largest-possible `U` which fits in `self`.
537 ///
538 /// # Safety
539 ///
540 /// The caller may assume that this implementation is correct, and may rely
541 /// on that assumption for the soundness of their code. In particular, the
542 /// caller may assume that, if `try_cast_into` returns `Some((ptr,
543 /// remainder))`, then `ptr` and `remainder` refer to non-overlapping byte
544 /// ranges within `self`, and that `ptr` and `remainder` entirely cover
545 /// `self`. Finally:
546 /// - If this is a prefix cast, `ptr` has the same address as `self`.
547 /// - If this is a suffix cast, `remainder` has the same address as `self`.
548 #[inline]
549 pub(crate) fn try_cast_into<U>(
550 self,
551 cast_type: CastType,
552 meta: Option<U::PointerMetadata>,
553 ) -> Result<(PtrInner<'a, U>, PtrInner<'a, [u8]>), CastError<Self, U>>
554 where
555 U: 'a + ?Sized + KnownLayout,
556 {
557 // PANICS: By invariant, the byte range addressed by
558 // `self.as_non_null()` does not wrap around the address space. This
559 // implies that the sum of the address (represented as a `usize`) and
560 // length do not overflow `usize`, as required by
561 // `validate_cast_and_convert_metadata`. Thus, this call to
562 // `validate_cast_and_convert_metadata` will only panic if `U` is a DST
563 // whose trailing slice element is zero-sized.
564 let maybe_metadata = MetadataOf::<U>::validate_cast_and_convert_metadata(
565 AsAddress::addr(self.as_ptr()),
566 self.meta(),
567 cast_type,
568 meta,
569 );
570
571 let (elems, split_at) = match maybe_metadata {
572 Ok((elems, split_at)) => (elems, split_at),
573 Err(MetadataCastError::Alignment) => {
574 // SAFETY: Since `validate_cast_and_convert_metadata` returned
575 // an alignment error, `U` must have an alignment requirement
576 // greater than one.
577 let err = unsafe { AlignmentError::<_, U>::new_unchecked(self) };
578 return Err(CastError::Alignment(err));
579 }
580 Err(MetadataCastError::Size) => return Err(CastError::Size(SizeError::new(self))),
581 };
582
583 // SAFETY: `validate_cast_and_convert_metadata` promises to return
584 // `split_at <= self.meta()`.
585 //
586 // Lemma 0: `l_slice` and `r_slice` are non-overlapping. Proof: By
587 // contract on `PtrInner::split_at_unchecked`, the produced `PtrInner`s
588 // are always non-overlapping if `self` is a `[T]`; here it is a `[u8]`.
589 let (l_slice, r_slice) = unsafe { self.split_at_unchecked(split_at) };
590
591 let (target, remainder) = match cast_type {
592 CastType::Prefix => (l_slice, r_slice),
593 CastType::Suffix => (r_slice, l_slice),
594 };
595
596 let base = target.as_non_null().cast::<u8>();
597
598 let ptr = U::raw_from_ptr_len(base, elems.get());
599
600 // SAFETY:
601 // 0. By invariant, if `target`'s referent is not zero sized, then
602 // `target` has provenance valid for some Rust allocation, `A`.
603 // Because `ptr` is derived from `target` via provenance-preserving
604 // operations, `ptr` will also have provenance valid for its entire
605 // referent.
606 // 1. `validate_cast_and_convert_metadata` promises that the object
607 // described by `elems` and `split_at` lives at a byte range which is
608 // a subset of the input byte range. Thus, by invariant, if
609 // `target`'s referent is not zero sized, then `target` refers to an
610 // allocation which is guaranteed to live for at least `'a`, and thus
611 // so does `ptr`.
612 Ok((unsafe { PtrInner::new(ptr) }, remainder))
613 }
614}
615
616#[cfg(test)]
617mod tests {
618 use super::*;
619 use crate::*;
620
621 #[test]
622 fn test_meta() {
623 let arr = [1; 16];
624 let dst = <[u8]>::ref_from_bytes(&arr[..]).unwrap();
625 let ptr = PtrInner::from_ref(dst);
626 assert_eq!(ptr.meta().get(), 16);
627
628 // SAFETY: 8 is less than 16
629 let ptr = unsafe { ptr.with_meta(8) };
630
631 assert_eq!(ptr.meta().get(), 8);
632 }
633
634 #[test]
635 fn test_split_at() {
636 fn test_split_at<const OFFSET: usize, const BUFFER_SIZE: usize>() {
637 #[derive(FromBytes, KnownLayout, SplitAt, Immutable)]
638 #[repr(C)]
639 struct SliceDst<const OFFSET: usize> {
640 prefix: [u8; OFFSET],
641 trailing: [u8],
642 }
643
644 let n: usize = BUFFER_SIZE - OFFSET;
645 let arr = [1; BUFFER_SIZE];
646 let dst = SliceDst::<OFFSET>::ref_from_bytes(&arr[..]).unwrap();
647 let ptr = PtrInner::from_ref(dst);
648 for i in 0..=n {
649 assert_eq!(ptr.meta().get(), n);
650 // SAFETY: `i` is in bounds by construction.
651 let i = unsafe { MetadataOf::new_unchecked(i) };
652 // SAFETY: `i` is in bounds by construction.
653 let (l, r) = unsafe { ptr.split_at_unchecked(i) };
654 // SAFETY: Points to a valid value by construction.
655 #[allow(clippy::undocumented_unsafe_blocks, clippy::as_conversions)]
656 // Clippy false positive
657 let l_sum: usize = l
658 .trailing_slice()
659 .iter()
660 .map(|ptr| unsafe { core::ptr::read_unaligned(ptr.as_ptr()) } as usize)
661 .sum();
662 // SAFETY: Points to a valid value by construction.
663 #[allow(clippy::undocumented_unsafe_blocks, clippy::as_conversions)]
664 // Clippy false positive
665 let r_sum: usize = r
666 .iter()
667 .map(|ptr| unsafe { core::ptr::read_unaligned(ptr.as_ptr()) } as usize)
668 .sum();
669 assert_eq!(l_sum, i.get());
670 assert_eq!(r_sum, n - i.get());
671 assert_eq!(l_sum + r_sum, n);
672 }
673 }
674
675 test_split_at::<0, 16>();
676 test_split_at::<1, 17>();
677 test_split_at::<2, 18>();
678 }
679
680 #[test]
681 fn test_trailing_slice() {
682 fn test_trailing_slice<const OFFSET: usize, const BUFFER_SIZE: usize>() {
683 #[derive(FromBytes, KnownLayout, SplitAt, Immutable)]
684 #[repr(C)]
685 struct SliceDst<const OFFSET: usize> {
686 prefix: [u8; OFFSET],
687 trailing: [u8],
688 }
689
690 let n: usize = BUFFER_SIZE - OFFSET;
691 let arr = [1; BUFFER_SIZE];
692 let dst = SliceDst::<OFFSET>::ref_from_bytes(&arr[..]).unwrap();
693 let ptr = PtrInner::from_ref(dst);
694
695 assert_eq!(ptr.meta().get(), n);
696 let trailing = ptr.trailing_slice();
697 assert_eq!(trailing.meta().get(), n);
698
699 assert_eq!(
700 // SAFETY: We assume this to be sound for the sake of this test,
701 // which will fail, here, in miri, if the safety precondition of
702 // `offset_of` is not satisfied.
703 unsafe {
704 #[allow(clippy::as_conversions)]
705 let offset = (trailing.as_ptr() as *mut u8).offset_from(ptr.as_ptr() as *mut _);
706 offset
707 },
708 isize::try_from(OFFSET).unwrap(),
709 );
710
711 // SAFETY: Points to a valid value by construction.
712 #[allow(clippy::undocumented_unsafe_blocks, clippy::as_conversions)]
713 // Clippy false positive
714 let trailing: usize = trailing
715 .iter()
716 .map(|ptr| unsafe { core::ptr::read_unaligned(ptr.as_ptr()) } as usize)
717 .sum();
718
719 assert_eq!(trailing, n);
720 }
721
722 test_trailing_slice::<0, 16>();
723 test_trailing_slice::<1, 17>();
724 test_trailing_slice::<2, 18>();
725 }
726 #[test]
727 fn test_ptr_inner_clone() {
728 let mut x = 0u8;
729 let p = PtrInner::from_mut(&mut x);
730 #[allow(clippy::clone_on_copy)]
731 let p2 = p.clone();
732 assert_eq!(p.as_non_null(), p2.as_non_null());
733 }
734}