// SPDX-License-Identifier: (BSD-2-Clause OR Apache-2.0) OR MIT // Copyright 2024 The Fuchsia Authors//// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.// This file may not be copied, modified, or distributed except according to// those terms. use core::{marker::PhantomData, ops::Range, ptr::NonNull}; pub use _def::PtrInner; #[allow(unused_imports)]use crate::util::polyfills::NumExt as _;use crate::{ layout::{CastType, MetadataCastError}, pointer::cast, util::AsAddress, AlignmentError, CastError, KnownLayout, MetadataOf, SizeError, SplitAt,}; mod _def { use super::*; /// The inner pointer stored inside a [`Ptr`][crate::Ptr]. /// /// `PtrInner<'a, T>` is [covariant] in `'a` and invariant in `T`. /// /// [covariant]: https://doc.rust-lang.org/reference/subtyping.html #[allow(missing_debug_implementations)] pub struct PtrInner<'a, T> where T: ?Sized, { /// # Invariants /// /// 0. If `ptr`'s referent is not zero sized, then `ptr` has valid /// provenance for its referent, which is entirely contained in some /// Rust allocation, `A`. /// 1. If `ptr`'s referent is not zero sized, `A` is guaranteed to live /// for at least `'a`. /// /// # Postconditions /// /// By virtue of these invariants, code may assume the following, which /// are logical implications of the invariants: /// - `ptr`'s referent is not larger than `isize::MAX` bytes \[1\] /// - `ptr`'s referent does not wrap around the address space \[1\] /// /// \[1\] Per <https://doc.rust-lang.org/1.85.0/std/ptr/index.html#allocated-object>: /// /// For any allocated object with `base` address, `size`, and a set of /// `addresses`, the following are guaranteed: /// ... /// - `size <= isize::MAX` /// /// As a consequence of these guarantees, given any address `a` within /// the set of addresses of an allocated object: /// ... /// - It is guaranteed that, given `o = a - base` (i.e., the offset of /// `a` within the allocated object), `base + o` will not wrap /// around the address space (in other words, will not overflow /// `usize`) ptr: NonNull<T>, // SAFETY: `&'a UnsafeCell<T>` is covariant in `'a` and invariant in `T` // [1]. We use this construction rather than the equivalent `&mut T`, // because our MSRV of 1.65 prohibits `&mut` types in const contexts. // // [1] https://doc.rust-lang.org/1.81.0/reference/subtyping.html#variance _marker: PhantomData<&'a core::cell::UnsafeCell<T>>, } impl<'a, T: 'a + ?Sized> Copy for PtrInner<'a, T> {} impl<'a, T: 'a + ?Sized> Clone for PtrInner<'a, T> { #[inline(always)] fn clone(&self) -> PtrInner<'a, T> { // SAFETY: None of the invariants on `ptr` are affected by having // multiple copies of a `PtrInner`. *self } } impl<'a, T: 'a + ?Sized> PtrInner<'a, T> { /// Constructs a `Ptr` from a [`NonNull`]. /// /// # Safety /// /// The caller promises that: /// /// 0. If `ptr`'s referent is not zero sized, then `ptr` has valid /// provenance for its referent, which is entirely contained in some /// Rust allocation, `A`. /// 1. If `ptr`'s referent is not zero sized, `A` is guaranteed to live /// for at least `'a`. #[inline(always)] #[must_use] pub const unsafe fn new(ptr: NonNull<T>) -> PtrInner<'a, T> { // SAFETY: The caller has promised to satisfy all safety invariants // of `PtrInner`. Self { ptr, _marker: PhantomData } } /// Converts this `PtrInner<T>` to a [`NonNull<T>`]. /// /// Note that this method does not consume `self`. The caller should /// watch out for `unsafe` code which uses the returned `NonNull` in a /// way that violates the safety invariants of `self`. #[inline(always)] #[must_use] pub const fn as_non_null(&self) -> NonNull<T> { self.ptr } /// Converts this `PtrInner<T>` to a [`*mut T`]. /// /// Note that this method does not consume `self`. The caller should /// watch out for `unsafe` code which uses the returned `*mut T` in a /// way that violates the safety invariants of `self`. #[inline(always)] #[must_use] pub const fn as_ptr(&self) -> *mut T { self.ptr.as_ptr() } }} impl<'a, T: ?Sized> PtrInner<'a, T> { /// Constructs a `PtrInner` from a reference. #[inline] pub fn from_ref(ptr: &'a T) -> Self { let ptr = NonNull::from(ptr); // SAFETY: // 0. If `ptr`'s referent is not zero sized, then `ptr`, by invariant on // `&'a T` [1], has valid provenance for its referent, which is // entirely contained in some Rust allocation, `A`. // 1. If `ptr`'s referent is not zero sized, then `A`, by invariant on // `&'a T`, is guaranteed to live for at least `'a`. // // [1] Per https://doc.rust-lang.org/1.85.0/std/primitive.reference.html#safety: // // For all types, `T: ?Sized`, and for all `t: &T` or `t: &mut T`, // when such values cross an API boundary, the following invariants // must generally be upheld: // ... // - if `size_of_val(t) > 0`, then `t` is dereferenceable for // `size_of_val(t)` many bytes // // If `t` points at address `a`, being “dereferenceable” for N bytes // means that the memory range `[a, a + N)` is all contained within a // single allocated object. unsafe { Self::new(ptr) } } /// Constructs a `PtrInner` from a mutable reference. #[inline] pub fn from_mut(ptr: &'a mut T) -> Self { let ptr = NonNull::from(ptr); // SAFETY: // 0. If `ptr`'s referent is not zero sized, then `ptr`, by invariant on // `&'a mut T` [1], has valid provenance for its referent, which is // entirely contained in some Rust allocation, `A`. // 1. If `ptr`'s referent is not zero sized, then `A`, by invariant on // `&'a mut T`, is guaranteed to live for at least `'a`. // // [1] Per https://doc.rust-lang.org/1.85.0/std/primitive.reference.html#safety: // // For all types, `T: ?Sized`, and for all `t: &T` or `t: &mut T`, // when such values cross an API boundary, the following invariants // must generally be upheld: // ... // - if `size_of_val(t) > 0`, then `t` is dereferenceable for // `size_of_val(t)` many bytes // // If `t` points at address `a`, being “dereferenceable” for N bytes // means that the memory range `[a, a + N)` is all contained within a // single allocated object. unsafe { Self::new(ptr) } } /// # Safety /// /// The caller may assume that the resulting `PtrInner` addresses the subset /// of the bytes of `self`'s referent addressed by `C::project(self)`. #[must_use] #[inline(always)] pub fn project<U: ?Sized, C: cast::Project<T, U>>(self) -> PtrInner<'a, U> { let projected_raw = C::project(self); // SAFETY: `self`'s referent lives at a `NonNull` address, and is either // zero-sized or lives in an allocation. In either case, it does not // wrap around the address space [1], and so none of the addresses // contained in it or one-past-the-end of it are null. // // By invariant on `C: Project`, `C::project` is a provenance-preserving // projection which preserves or shrinks the set of referent bytes, so // `projected_raw` references a subset of `self`'s referent, and so it // cannot be null. // // [1] https://doc.rust-lang.org/1.92.0/std/ptr/index.html#allocation let projected_non_null = unsafe { NonNull::new_unchecked(projected_raw) }; // SAFETY: As described in the preceding safety comment, `projected_raw`, // and thus `projected_non_null`, addresses a subset of `self`'s // referent. Thus, `projected_non_null` either: // - Addresses zero bytes or, // - Addresses a subset of the referent of `self`. In this case, `self` // has provenance for its referent, which lives in an allocation. // Since `projected_non_null` was constructed using a sequence of // provenance-preserving operations, it also has provenance for its // referent and that referent lives in an allocation. By invariant on // `self`, that allocation lives for `'a`. unsafe { PtrInner::new(projected_non_null) } }} #[allow(clippy::needless_lifetimes)]impl<'a, T> PtrInner<'a, T>where T: ?Sized + KnownLayout,{ /// Extracts the metadata of this `ptr`. #[inline] #[must_use] pub fn meta(self) -> MetadataOf<T> { let meta = T::pointer_to_metadata(self.as_ptr()); // SAFETY: By invariant on `PtrInner`, `self.as_non_null()` addresses no // more than `isize::MAX` bytes. unsafe { MetadataOf::new_unchecked(meta) } } /// Produces a `PtrInner` with the same address and provenance as `self` but /// the given `meta`. /// /// # Safety /// /// The caller promises that if `self`'s referent is not zero sized, then /// a pointer constructed from its address with the given `meta` metadata /// will address a subset of the allocation pointed to by `self`. #[inline] #[must_use] pub unsafe fn with_meta(self, meta: T::PointerMetadata) -> Self where T: KnownLayout, { let raw = T::raw_from_ptr_len(self.as_non_null().cast(), meta); // SAFETY: // // Lemma 0: `raw` either addresses zero bytes, or addresses a subset of // the allocation pointed to by `self` and has the same // provenance as `self`. Proof: `raw` is constructed using // provenance-preserving operations, and the caller has // promised that, if `self`'s referent is not zero-sized, the // resulting pointer addresses a subset of the allocation // pointed to by `self`. // // 0. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not // zero sized, then `ptr` is derived from some valid Rust allocation, // `A`. // 1. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not // zero sized, then `ptr` has valid provenance for `A`. // 2. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not // zero sized, then `ptr` addresses a byte range which is entirely // contained in `A`. // 3. Per Lemma 0 and by invariant on `self`, `ptr` addresses a byte // range whose length fits in an `isize`. // 4. Per Lemma 0 and by invariant on `self`, `ptr` addresses a byte // range which does not wrap around the address space. // 5. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not // zero sized, then `A` is guaranteed to live for at least `'a`. unsafe { PtrInner::new(raw) } }} #[allow(clippy::needless_lifetimes)]impl<'a, T> PtrInner<'a, T>where T: ?Sized + KnownLayout<PointerMetadata = usize>,{ /// Splits `T` in two. /// /// # Safety /// /// The caller promises that: /// - `l_len.get() <= self.meta()`. /// /// ## (Non-)Overlap /// /// Given `let (left, right) = ptr.split_at(l_len)`, it is guaranteed that /// `left` and `right` are contiguous and non-overlapping if /// `l_len.padding_needed_for() == 0`. This is true for all `[T]`. /// /// If `l_len.padding_needed_for() != 0`, then the left pointer will overlap /// the right pointer to satisfy `T`'s padding requirements. #[inline] #[must_use] pub unsafe fn split_at_unchecked( self, l_len: crate::util::MetadataOf<T>, ) -> (Self, PtrInner<'a, [T::Elem]>) where T: SplitAt, { let l_len = l_len.get(); // SAFETY: The caller promises that `l_len.get() <= self.meta()`. // Trivially, `0 <= l_len`. let left = unsafe { self.with_meta(l_len) }; let right = self.trailing_slice(); // SAFETY: The caller promises that `l_len <= self.meta() = slf.meta()`. // Trivially, `slf.meta() <= slf.meta()`. let right = unsafe { right.slice_unchecked(l_len..self.meta().get()) }; // SAFETY: If `l_len.padding_needed_for() == 0`, then `left` and `right` // are non-overlapping. Proof: `left` is constructed `slf` with `l_len` // as its (exclusive) upper bound. If `l_len.padding_needed_for() == 0`, // then `left` requires no trailing padding following its final element. // Since `right` is constructed from `slf`'s trailing slice with `l_len` // as its (inclusive) lower bound, no byte is referred to by both // pointers. // // Conversely, `l_len.padding_needed_for() == N`, where `N // > 0`, `left` requires `N` bytes of trailing padding following its // final element. Since `right` is constructed from the trailing slice // of `slf` with `l_len` as its (inclusive) lower bound, the first `N` // bytes of `right` are aliased by `left`. (left, right) } /// Produces the trailing slice of `self`. #[inline] #[must_use] pub fn trailing_slice(self) -> PtrInner<'a, [T::Elem]> where T: SplitAt, { let offset = crate::trailing_slice_layout::<T>().offset; let bytes = self.as_non_null().cast::<u8>().as_ptr(); // SAFETY: // - By invariant on `T: KnownLayout`, `T::LAYOUT` describes `T`'s // layout. `offset` is the offset of the trailing slice within `T`, // which is by definition in-bounds or one byte past the end of any // `T`, regardless of metadata. By invariant on `PtrInner`, `self` // (and thus `bytes`) points to a byte range of size `<= isize::MAX`, // and so `offset <= isize::MAX`. Since `size_of::<u8>() == 1`, // `offset * size_of::<u8>() <= isize::MAX`. // - If `offset > 0`, then by invariant on `PtrInner`, `self` (and thus // `bytes`) points to a byte range entirely contained within the same // allocated object as `self`. As explained above, this offset results // in a pointer to or one byte past the end of this allocated object. let bytes = unsafe { bytes.add(offset) }; // SAFETY: By the preceding safety argument, `bytes` is within or one // byte past the end of the same allocated object as `self`, which // ensures that it is non-null. let bytes = unsafe { NonNull::new_unchecked(bytes) }; let ptr = KnownLayout::raw_from_ptr_len(bytes, self.meta().get()); // SAFETY: // 0. If `ptr`'s referent is not zero sized, then `ptr` is derived from // some valid Rust allocation, `A`, because `ptr` is derived from // the same allocated object as `self`. // 1. If `ptr`'s referent is not zero sized, then `ptr` has valid // provenance for `A` because `raw` is derived from the same // allocated object as `self` via provenance-preserving operations. // 2. If `ptr`'s referent is not zero sized, then `ptr` addresses a byte // range which is entirely contained in `A`, by previous safety proof // on `bytes`. // 3. `ptr` addresses a byte range whose length fits in an `isize`, by // consequence of #2. // 4. `ptr` addresses a byte range which does not wrap around the // address space, by consequence of #2. // 5. If `ptr`'s referent is not zero sized, then `A` is guaranteed to // live for at least `'a`, because `ptr` is derived from `self`. unsafe { PtrInner::new(ptr) } }} #[allow(clippy::needless_lifetimes)]impl<'a, T> PtrInner<'a, [T]> { /// Creates a pointer which addresses the given `range` of self. /// /// # Safety /// /// `range` is a valid range (`start <= end`) and `end <= self.meta()`. #[inline] #[must_use] pub unsafe fn slice_unchecked(self, range: Range<usize>) -> Self { let base = self.as_non_null().cast::<T>().as_ptr(); // SAFETY: The caller promises that `start <= end <= self.meta()`. By // invariant, if `self`'s referent is not zero-sized, then `self` refers // to a byte range which is contained within a single allocation, which // is no more than `isize::MAX` bytes long, and which does not wrap // around the address space. Thus, this pointer arithmetic remains // in-bounds of the same allocation, and does not wrap around the // address space. The offset (in bytes) does not overflow `isize`. // // If `self`'s referent is zero-sized, then these conditions are // trivially satisfied. let base = unsafe { base.add(range.start) }; // SAFETY: The caller promises that `start <= end`, and so this will not // underflow. #[allow(unstable_name_collisions)] let len = unsafe { range.end.unchecked_sub(range.start) }; let ptr = core::ptr::slice_from_raw_parts_mut(base, len); // SAFETY: By invariant, `self`'s referent is either a ZST or lives // entirely in an allocation. `ptr` points inside of or one byte past // the end of that referent. Thus, in either case, `ptr` is non-null. let ptr = unsafe { NonNull::new_unchecked(ptr) }; // SAFETY: // // Lemma 0: `ptr` addresses a subset of the bytes addressed by `self`, // and has the same provenance. Proof: The caller guarantees // that `start <= end <= self.meta()`. Thus, `base` is // in-bounds of `self`, and `base + (end - start)` is also // in-bounds of self. Finally, `ptr` is constructed using // provenance-preserving operations. // // 0. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not // zero sized, then `ptr` has valid provenance for its referent, // which is entirely contained in some Rust allocation, `A`. // 1. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not // zero sized, then `A` is guaranteed to live for at least `'a`. unsafe { PtrInner::new(ptr) } } /// Iteratively projects the elements `PtrInner<T>` from `PtrInner<[T]>`. #[inline] pub fn iter(&self) -> impl Iterator<Item = PtrInner<'a, T>> { // FIXME(#429): Once `NonNull::cast` documents that it preserves // provenance, cite those docs. let base = self.as_non_null().cast::<T>().as_ptr(); (0..self.meta().get()).map(move |i| { // FIXME(https://github.com/rust-lang/rust/issues/74265): Use // `NonNull::get_unchecked_mut`. // SAFETY: If the following conditions are not satisfied // `pointer::cast` may induce Undefined Behavior [1]: // // > - The computed offset, `count * size_of::<T>()` bytes, must not // > overflow `isize``. // > - If the computed offset is non-zero, then `self` must be // > derived from a pointer to some allocated object, and the // > entire memory range between `self` and the result must be in // > bounds of that allocated object. In particular, this range // > must not “wrap around” the edge of the address space. // // [1] https://doc.rust-lang.org/std/primitive.pointer.html#method.add // // We satisfy both of these conditions here: // - By invariant on `Ptr`, `self` addresses a byte range whose // length fits in an `isize`. Since `elem` is contained in `self`, // the computed offset of `elem` must fit within `isize.` // - If the computed offset is non-zero, then this means that the // referent is not zero-sized. In this case, `base` points to an // allocated object (by invariant on `self`). Thus: // - By contract, `self.meta()` accurately reflects the number of // elements in the slice. `i` is in bounds of `c.meta()` by // construction, and so the result of this addition cannot // overflow past the end of the allocation referred to by `c`. // - By invariant on `Ptr`, `self` addresses a byte range which // does not wrap around the address space. Since `elem` is // contained in `self`, the computed offset of `elem` must wrap // around the address space. // // FIXME(#429): Once `pointer::add` documents that it preserves // provenance, cite those docs. let elem = unsafe { base.add(i) }; // SAFETY: `elem` must not be null. `base` is constructed from a // `NonNull` pointer, and the addition that produces `elem` must not // overflow or wrap around, so `elem >= base > 0`. // // FIXME(#429): Once `NonNull::new_unchecked` documents that it // preserves provenance, cite those docs. let elem = unsafe { NonNull::new_unchecked(elem) }; // SAFETY: The safety invariants of `Ptr::new` (see definition) are // satisfied: // 0. If `elem`'s referent is not zero sized, then `elem` has valid // provenance for its referent, because it derived from `self` // using a series of provenance-preserving operations, and // because `self` has valid provenance for its referent. By the // same argument, `elem`'s referent is entirely contained within // the same allocated object as `self`'s referent. // 1. If `elem`'s referent is not zero sized, then the allocation of // `elem` is guaranteed to live for at least `'a`, because `elem` // is entirely contained in `self`, which lives for at least `'a` // by invariant on `Ptr`. unsafe { PtrInner::new(elem) }Lines 1–500 of 754. Load more
// SPDX-License-Identifier: (BSD-2-Clause OR Apache-2.0) OR MIT // Copyright 2024 The Fuchsia Authors // // Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0 // <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT // license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option. // This file may not be copied, modified, or distributed except according to // those terms. use core::{marker::PhantomData, ops::Range, ptr::NonNull}; pub use _def::PtrInner; #[allow(unused_imports)] use crate::util::polyfills::NumExt as _; use crate::{ layout::{CastType, MetadataCastError}, pointer::cast, util::AsAddress, AlignmentError, CastError, KnownLayout, MetadataOf, SizeError, SplitAt, }; mod _def { use super::*; /// The inner pointer stored inside a [`Ptr`][crate::Ptr]. /// /// `PtrInner<'a, T>` is [covariant] in `'a` and invariant in `T`. /// /// [covariant]: https://doc.rust-lang.org/reference/subtyping.html #[allow(missing_debug_implementations)] pub struct PtrInner<'a, T> where T: ?Sized, { /// # Invariants /// /// 0. If `ptr`'s referent is not zero sized, then `ptr` has valid /// provenance for its referent, which is entirely contained in some /// Rust allocation, `A`. /// 1. If `ptr`'s referent is not zero sized, `A` is guaranteed to live /// for at least `'a`. /// /// # Postconditions /// /// By virtue of these invariants, code may assume the following, which /// are logical implications of the invariants: /// - `ptr`'s referent is not larger than `isize::MAX` bytes \[1\] /// - `ptr`'s referent does not wrap around the address space \[1\] /// /// \[1\] Per <https://doc.rust-lang.org/1.85.0/std/ptr/index.html#allocated-object>: /// /// For any allocated object with `base` address, `size`, and a set of /// `addresses`, the following are guaranteed: /// ... /// - `size <= isize::MAX` /// /// As a consequence of these guarantees, given any address `a` within /// the set of addresses of an allocated object: /// ... /// - It is guaranteed that, given `o = a - base` (i.e., the offset of /// `a` within the allocated object), `base + o` will not wrap /// around the address space (in other words, will not overflow /// `usize`) ptr: NonNull<T>, // SAFETY: `&'a UnsafeCell<T>` is covariant in `'a` and invariant in `T` // [1]. We use this construction rather than the equivalent `&mut T`, // because our MSRV of 1.65 prohibits `&mut` types in const contexts. // // [1] https://doc.rust-lang.org/1.81.0/reference/subtyping.html#variance _marker: PhantomData<&'a core::cell::UnsafeCell<T>>, } impl<'a, T: 'a + ?Sized> Copy for PtrInner<'a, T> {} impl<'a, T: 'a + ?Sized> Clone for PtrInner<'a, T> { #[inline(always)] fn clone(&self) -> PtrInner<'a, T> { // SAFETY: None of the invariants on `ptr` are affected by having // multiple copies of a `PtrInner`. *self } } impl<'a, T: 'a + ?Sized> PtrInner<'a, T> { /// Constructs a `Ptr` from a [`NonNull`]. /// /// # Safety /// /// The caller promises that: /// /// 0. If `ptr`'s referent is not zero sized, then `ptr` has valid /// provenance for its referent, which is entirely contained in some /// Rust allocation, `A`. /// 1. If `ptr`'s referent is not zero sized, `A` is guaranteed to live /// for at least `'a`. #[inline(always)] #[must_use] pub const unsafe fn new(ptr: NonNull<T>) -> PtrInner<'a, T> { // SAFETY: The caller has promised to satisfy all safety invariants // of `PtrInner`. Self { ptr, _marker: PhantomData } } /// Converts this `PtrInner<T>` to a [`NonNull<T>`]. /// /// Note that this method does not consume `self`. The caller should /// watch out for `unsafe` code which uses the returned `NonNull` in a /// way that violates the safety invariants of `self`. #[inline(always)] #[must_use] pub const fn as_non_null(&self) -> NonNull<T> { self.ptr } /// Converts this `PtrInner<T>` to a [`*mut T`]. /// /// Note that this method does not consume `self`. The caller should /// watch out for `unsafe` code which uses the returned `*mut T` in a /// way that violates the safety invariants of `self`. #[inline(always)] #[must_use] pub const fn as_ptr(&self) -> *mut T { self.ptr.as_ptr() } } } impl<'a, T: ?Sized> PtrInner<'a, T> { /// Constructs a `PtrInner` from a reference. #[inline] pub fn from_ref(ptr: &'a T) -> Self { let ptr = NonNull::from(ptr); // SAFETY: // 0. If `ptr`'s referent is not zero sized, then `ptr`, by invariant on // `&'a T` [1], has valid provenance for its referent, which is // entirely contained in some Rust allocation, `A`. // 1. If `ptr`'s referent is not zero sized, then `A`, by invariant on // `&'a T`, is guaranteed to live for at least `'a`. // // [1] Per https://doc.rust-lang.org/1.85.0/std/primitive.reference.html#safety: // // For all types, `T: ?Sized`, and for all `t: &T` or `t: &mut T`, // when such values cross an API boundary, the following invariants // must generally be upheld: // ... // - if `size_of_val(t) > 0`, then `t` is dereferenceable for // `size_of_val(t)` many bytes // // If `t` points at address `a`, being “dereferenceable” for N bytes // means that the memory range `[a, a + N)` is all contained within a // single allocated object. unsafe { Self::new(ptr) } } /// Constructs a `PtrInner` from a mutable reference. #[inline] pub fn from_mut(ptr: &'a mut T) -> Self { let ptr = NonNull::from(ptr); // SAFETY: // 0. If `ptr`'s referent is not zero sized, then `ptr`, by invariant on // `&'a mut T` [1], has valid provenance for its referent, which is // entirely contained in some Rust allocation, `A`. // 1. If `ptr`'s referent is not zero sized, then `A`, by invariant on // `&'a mut T`, is guaranteed to live for at least `'a`. // // [1] Per https://doc.rust-lang.org/1.85.0/std/primitive.reference.html#safety: // // For all types, `T: ?Sized`, and for all `t: &T` or `t: &mut T`, // when such values cross an API boundary, the following invariants // must generally be upheld: // ... // - if `size_of_val(t) > 0`, then `t` is dereferenceable for // `size_of_val(t)` many bytes // // If `t` points at address `a`, being “dereferenceable” for N bytes // means that the memory range `[a, a + N)` is all contained within a // single allocated object. unsafe { Self::new(ptr) } } /// # Safety /// /// The caller may assume that the resulting `PtrInner` addresses the subset /// of the bytes of `self`'s referent addressed by `C::project(self)`. #[must_use] #[inline(always)] pub fn project<U: ?Sized, C: cast::Project<T, U>>(self) -> PtrInner<'a, U> { let projected_raw = C::project(self); // SAFETY: `self`'s referent lives at a `NonNull` address, and is either // zero-sized or lives in an allocation. In either case, it does not // wrap around the address space [1], and so none of the addresses // contained in it or one-past-the-end of it are null. // // By invariant on `C: Project`, `C::project` is a provenance-preserving // projection which preserves or shrinks the set of referent bytes, so // `projected_raw` references a subset of `self`'s referent, and so it // cannot be null. // // [1] https://doc.rust-lang.org/1.92.0/std/ptr/index.html#allocation let projected_non_null = unsafe { NonNull::new_unchecked(projected_raw) }; // SAFETY: As described in the preceding safety comment, `projected_raw`, // and thus `projected_non_null`, addresses a subset of `self`'s // referent. Thus, `projected_non_null` either: // - Addresses zero bytes or, // - Addresses a subset of the referent of `self`. In this case, `self` // has provenance for its referent, which lives in an allocation. // Since `projected_non_null` was constructed using a sequence of // provenance-preserving operations, it also has provenance for its // referent and that referent lives in an allocation. By invariant on // `self`, that allocation lives for `'a`. unsafe { PtrInner::new(projected_non_null) } } } #[allow(clippy::needless_lifetimes)] impl<'a, T> PtrInner<'a, T> where T: ?Sized + KnownLayout, { /// Extracts the metadata of this `ptr`. #[inline] #[must_use] pub fn meta(self) -> MetadataOf<T> { let meta = T::pointer_to_metadata(self.as_ptr()); // SAFETY: By invariant on `PtrInner`, `self.as_non_null()` addresses no // more than `isize::MAX` bytes. unsafe { MetadataOf::new_unchecked(meta) } } /// Produces a `PtrInner` with the same address and provenance as `self` but /// the given `meta`. /// /// # Safety /// /// The caller promises that if `self`'s referent is not zero sized, then /// a pointer constructed from its address with the given `meta` metadata /// will address a subset of the allocation pointed to by `self`. #[inline] #[must_use] pub unsafe fn with_meta(self, meta: T::PointerMetadata) -> Self where T: KnownLayout, { let raw = T::raw_from_ptr_len(self.as_non_null().cast(), meta); // SAFETY: // // Lemma 0: `raw` either addresses zero bytes, or addresses a subset of // the allocation pointed to by `self` and has the same // provenance as `self`. Proof: `raw` is constructed using // provenance-preserving operations, and the caller has // promised that, if `self`'s referent is not zero-sized, the // resulting pointer addresses a subset of the allocation // pointed to by `self`. // // 0. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not // zero sized, then `ptr` is derived from some valid Rust allocation, // `A`. // 1. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not // zero sized, then `ptr` has valid provenance for `A`. // 2. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not // zero sized, then `ptr` addresses a byte range which is entirely // contained in `A`. // 3. Per Lemma 0 and by invariant on `self`, `ptr` addresses a byte // range whose length fits in an `isize`. // 4. Per Lemma 0 and by invariant on `self`, `ptr` addresses a byte // range which does not wrap around the address space. // 5. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not // zero sized, then `A` is guaranteed to live for at least `'a`. unsafe { PtrInner::new(raw) } } } #[allow(clippy::needless_lifetimes)] impl<'a, T> PtrInner<'a, T> where T: ?Sized + KnownLayout<PointerMetadata = usize>, { /// Splits `T` in two. /// /// # Safety /// /// The caller promises that: /// - `l_len.get() <= self.meta()`. /// /// ## (Non-)Overlap /// /// Given `let (left, right) = ptr.split_at(l_len)`, it is guaranteed that /// `left` and `right` are contiguous and non-overlapping if /// `l_len.padding_needed_for() == 0`. This is true for all `[T]`. /// /// If `l_len.padding_needed_for() != 0`, then the left pointer will overlap /// the right pointer to satisfy `T`'s padding requirements. #[inline] #[must_use] pub unsafe fn split_at_unchecked( self, l_len: crate::util::MetadataOf<T>, ) -> (Self, PtrInner<'a, [T::Elem]>) where T: SplitAt, { let l_len = l_len.get(); // SAFETY: The caller promises that `l_len.get() <= self.meta()`. // Trivially, `0 <= l_len`. let left = unsafe { self.with_meta(l_len) }; let right = self.trailing_slice(); // SAFETY: The caller promises that `l_len <= self.meta() = slf.meta()`. // Trivially, `slf.meta() <= slf.meta()`. let right = unsafe { right.slice_unchecked(l_len..self.meta().get()) }; // SAFETY: If `l_len.padding_needed_for() == 0`, then `left` and `right` // are non-overlapping. Proof: `left` is constructed `slf` with `l_len` // as its (exclusive) upper bound. If `l_len.padding_needed_for() == 0`, // then `left` requires no trailing padding following its final element. // Since `right` is constructed from `slf`'s trailing slice with `l_len` // as its (inclusive) lower bound, no byte is referred to by both // pointers. // // Conversely, `l_len.padding_needed_for() == N`, where `N // > 0`, `left` requires `N` bytes of trailing padding following its // final element. Since `right` is constructed from the trailing slice // of `slf` with `l_len` as its (inclusive) lower bound, the first `N` // bytes of `right` are aliased by `left`. (left, right) } /// Produces the trailing slice of `self`. #[inline] #[must_use] pub fn trailing_slice(self) -> PtrInner<'a, [T::Elem]> where T: SplitAt, { let offset = crate::trailing_slice_layout::<T>().offset; let bytes = self.as_non_null().cast::<u8>().as_ptr(); // SAFETY: // - By invariant on `T: KnownLayout`, `T::LAYOUT` describes `T`'s // layout. `offset` is the offset of the trailing slice within `T`, // which is by definition in-bounds or one byte past the end of any // `T`, regardless of metadata. By invariant on `PtrInner`, `self` // (and thus `bytes`) points to a byte range of size `<= isize::MAX`, // and so `offset <= isize::MAX`. Since `size_of::<u8>() == 1`, // `offset * size_of::<u8>() <= isize::MAX`. // - If `offset > 0`, then by invariant on `PtrInner`, `self` (and thus // `bytes`) points to a byte range entirely contained within the same // allocated object as `self`. As explained above, this offset results // in a pointer to or one byte past the end of this allocated object. let bytes = unsafe { bytes.add(offset) }; // SAFETY: By the preceding safety argument, `bytes` is within or one // byte past the end of the same allocated object as `self`, which // ensures that it is non-null. let bytes = unsafe { NonNull::new_unchecked(bytes) }; let ptr = KnownLayout::raw_from_ptr_len(bytes, self.meta().get()); // SAFETY: // 0. If `ptr`'s referent is not zero sized, then `ptr` is derived from // some valid Rust allocation, `A`, because `ptr` is derived from // the same allocated object as `self`. // 1. If `ptr`'s referent is not zero sized, then `ptr` has valid // provenance for `A` because `raw` is derived from the same // allocated object as `self` via provenance-preserving operations. // 2. If `ptr`'s referent is not zero sized, then `ptr` addresses a byte // range which is entirely contained in `A`, by previous safety proof // on `bytes`. // 3. `ptr` addresses a byte range whose length fits in an `isize`, by // consequence of #2. // 4. `ptr` addresses a byte range which does not wrap around the // address space, by consequence of #2. // 5. If `ptr`'s referent is not zero sized, then `A` is guaranteed to // live for at least `'a`, because `ptr` is derived from `self`. unsafe { PtrInner::new(ptr) } } } #[allow(clippy::needless_lifetimes)] impl<'a, T> PtrInner<'a, [T]> { /// Creates a pointer which addresses the given `range` of self. /// /// # Safety /// /// `range` is a valid range (`start <= end`) and `end <= self.meta()`. #[inline] #[must_use] pub unsafe fn slice_unchecked(self, range: Range<usize>) -> Self { let base = self.as_non_null().cast::<T>().as_ptr(); // SAFETY: The caller promises that `start <= end <= self.meta()`. By // invariant, if `self`'s referent is not zero-sized, then `self` refers // to a byte range which is contained within a single allocation, which // is no more than `isize::MAX` bytes long, and which does not wrap // around the address space. Thus, this pointer arithmetic remains // in-bounds of the same allocation, and does not wrap around the // address space. The offset (in bytes) does not overflow `isize`. // // If `self`'s referent is zero-sized, then these conditions are // trivially satisfied. let base = unsafe { base.add(range.start) }; // SAFETY: The caller promises that `start <= end`, and so this will not // underflow. #[allow(unstable_name_collisions)] let len = unsafe { range.end.unchecked_sub(range.start) }; let ptr = core::ptr::slice_from_raw_parts_mut(base, len); // SAFETY: By invariant, `self`'s referent is either a ZST or lives // entirely in an allocation. `ptr` points inside of or one byte past // the end of that referent. Thus, in either case, `ptr` is non-null. let ptr = unsafe { NonNull::new_unchecked(ptr) }; // SAFETY: // // Lemma 0: `ptr` addresses a subset of the bytes addressed by `self`, // and has the same provenance. Proof: The caller guarantees // that `start <= end <= self.meta()`. Thus, `base` is // in-bounds of `self`, and `base + (end - start)` is also // in-bounds of self. Finally, `ptr` is constructed using // provenance-preserving operations. // // 0. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not // zero sized, then `ptr` has valid provenance for its referent, // which is entirely contained in some Rust allocation, `A`. // 1. Per Lemma 0 and by invariant on `self`, if `ptr`'s referent is not // zero sized, then `A` is guaranteed to live for at least `'a`. unsafe { PtrInner::new(ptr) } } /// Iteratively projects the elements `PtrInner<T>` from `PtrInner<[T]>`. #[inline] pub fn iter(&self) -> impl Iterator<Item = PtrInner<'a, T>> { // FIXME(#429): Once `NonNull::cast` documents that it preserves // provenance, cite those docs. let base = self.as_non_null().cast::<T>().as_ptr(); (0..self.meta().get()).map(move |i| { // FIXME(https://github.com/rust-lang/rust/issues/74265): Use // `NonNull::get_unchecked_mut`. // SAFETY: If the following conditions are not satisfied // `pointer::cast` may induce Undefined Behavior [1]: // // > - The computed offset, `count * size_of::<T>()` bytes, must not // > overflow `isize``. // > - If the computed offset is non-zero, then `self` must be // > derived from a pointer to some allocated object, and the // > entire memory range between `self` and the result must be in // > bounds of that allocated object. In particular, this range // > must not “wrap around” the edge of the address space. // // [1] https://doc.rust-lang.org/std/primitive.pointer.html#method.add // // We satisfy both of these conditions here: // - By invariant on `Ptr`, `self` addresses a byte range whose // length fits in an `isize`. Since `elem` is contained in `self`, // the computed offset of `elem` must fit within `isize.` // - If the computed offset is non-zero, then this means that the // referent is not zero-sized. In this case, `base` points to an // allocated object (by invariant on `self`). Thus: // - By contract, `self.meta()` accurately reflects the number of // elements in the slice. `i` is in bounds of `c.meta()` by // construction, and so the result of this addition cannot // overflow past the end of the allocation referred to by `c`. // - By invariant on `Ptr`, `self` addresses a byte range which // does not wrap around the address space. Since `elem` is // contained in `self`, the computed offset of `elem` must wrap // around the address space. // // FIXME(#429): Once `pointer::add` documents that it preserves // provenance, cite those docs. let elem = unsafe { base.add(i) }; // SAFETY: `elem` must not be null. `base` is constructed from a // `NonNull` pointer, and the addition that produces `elem` must not // overflow or wrap around, so `elem >= base > 0`. // // FIXME(#429): Once `NonNull::new_unchecked` documents that it // preserves provenance, cite those docs. let elem = unsafe { NonNull::new_unchecked(elem) }; // SAFETY: The safety invariants of `Ptr::new` (see definition) are // satisfied: // 0. If `elem`'s referent is not zero sized, then `elem` has valid // provenance for its referent, because it derived from `self` // using a series of provenance-preserving operations, and // because `self` has valid provenance for its referent. By the // same argument, `elem`'s referent is entirely contained within // the same allocated object as `self`'s referent. // 1. If `elem`'s referent is not zero sized, then the allocation of // `elem` is guaranteed to live for at least `'a`, because `elem` // is entirely contained in `self`, which lives for at least `'a` // by invariant on `Ptr`. unsafe { PtrInner::new(elem) }