Vendor dependencies

This commit is contained in:
2026-08-01 16:11:49 +03:00
parent 7f139a0241
commit 6b5e7f0f8b
29706 changed files with 9575646 additions and 0 deletions
+434
View File
@@ -0,0 +1,434 @@
// 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.
//! Traits for types that encapsulate a `[u8]`.
//!
//! These traits are used to bound the `B` parameter of [`Ref`].
use core::{
cell,
ops::{Deref, DerefMut},
};
// For each trait polyfill, as soon as the corresponding feature is stable, the
// polyfill import will be unused because method/function resolution will prefer
// the inherent method/function over a trait method/function. Thus, we suppress
// the `unused_imports` warning.
//
// See the documentation on `util::polyfills` for more information.
#[allow(unused_imports)]
use crate::util::polyfills::{self, NonNullExt as _, NumExt as _};
#[cfg(doc)]
use crate::Ref;
/// A mutable or immutable reference to a byte slice.
///
/// `ByteSlice` abstracts over the mutability of a byte slice reference, and is
/// implemented for various special reference types such as
/// [`Ref<[u8]>`](core::cell::Ref) and [`RefMut<[u8]>`](core::cell::RefMut).
///
/// # Safety
///
/// Implementations of `ByteSlice` must promise that their implementations of
/// [`Deref`] and [`DerefMut`] are "stable". In particular, given `B: ByteSlice`
/// and `b: B`, two calls, each to either `b.deref()` or `b.deref_mut()`, must
/// return a byte slice with the same address and length. This must hold even if
/// the two calls are separated by an arbitrary sequence of calls to methods on
/// `ByteSlice`, [`ByteSliceMut`], [`IntoByteSlice`], or [`IntoByteSliceMut`],
/// or on their super-traits. This does *not* need to hold if the two calls are
/// separated by any method calls, field accesses, or field modifications *other
/// than* those from these traits.
///
/// Note that this also implies that, given `b: B`, the address and length
/// cannot be modified via objects other than `b`, either on the same thread or
/// on another thread.
pub unsafe trait ByteSlice: Deref<Target = [u8]> + Sized {}
/// A mutable reference to a byte slice.
///
/// `ByteSliceMut` abstracts over various ways of storing a mutable reference to
/// a byte slice, and is implemented for various special reference types such as
/// `RefMut<[u8]>`.
///
/// `ByteSliceMut` is a shorthand for [`ByteSlice`] and [`DerefMut`].
pub trait ByteSliceMut: ByteSlice + DerefMut {}
impl<B: ByteSlice + DerefMut> ByteSliceMut for B {}
/// A [`ByteSlice`] which can be copied without violating dereference stability.
///
/// # Safety
///
/// If `B: CopyableByteSlice`, then the dereference stability properties
/// required by [`ByteSlice`] (see that trait's safety documentation) do not
/// only hold regarding two calls to `b.deref()` or `b.deref_mut()`, but also
/// hold regarding `c.deref()` or `c.deref_mut()`, where `c` is produced by
/// copying `b`.
pub unsafe trait CopyableByteSlice: ByteSlice + Copy + CloneableByteSlice {}
/// A [`ByteSlice`] which can be cloned without violating dereference stability.
///
/// # Safety
///
/// If `B: CloneableByteSlice`, then the dereference stability properties
/// required by [`ByteSlice`] (see that trait's safety documentation) do not
/// only hold regarding two calls to `b.deref()` or `b.deref_mut()`, but also
/// hold regarding `c.deref()` or `c.deref_mut()`, where `c` is produced by
/// `b.clone()`, `b.clone().clone()`, etc.
pub unsafe trait CloneableByteSlice: ByteSlice + Clone {}
/// A [`ByteSlice`] that can be split in two.
///
/// # Safety
///
/// Unsafe code may depend for its soundness on the assumption that `split_at`
/// and `split_at_unchecked` are implemented correctly. In particular, given `B:
/// SplitByteSlice` and `b: B`, if `b.deref()` returns a byte slice with address
/// `addr` and length `len`, then if `split <= len`, both of these
/// invocations:
/// - `b.split_at(split)`
/// - `b.split_at_unchecked(split)`
///
/// ...will return `(first, second)` such that:
/// - `first`'s address is `addr` and its length is `split`
/// - `second`'s address is `addr + split` and its length is `len - split`
pub unsafe trait SplitByteSlice: ByteSlice {
/// Attempts to split `self` at the midpoint.
///
/// `s.split_at(mid)` returns `Ok((s[..mid], s[mid..]))` if `mid <=
/// s.deref().len()` and otherwise returns `Err(s)`.
///
/// # Safety
///
/// Unsafe code may rely on this function correctly implementing the above
/// functionality.
#[inline]
fn split_at(self, mid: usize) -> Result<(Self, Self), Self> {
if mid <= self.deref().len() {
// SAFETY: Above, we ensure that `mid <= self.deref().len()`. By
// invariant on `ByteSlice`, a supertrait of `SplitByteSlice`,
// `.deref()` is guaranteed to be "stable"; i.e., it will always
// dereference to a byte slice of the same address and length. Thus,
// we can be sure that the above precondition remains satisfied
// through the call to `split_at_unchecked`.
unsafe { Ok(self.split_at_unchecked(mid)) }
} else {
Err(self)
}
}
/// Splits the slice at the midpoint, possibly omitting bounds checks.
///
/// `s.split_at_unchecked(mid)` returns `s[..mid]` and `s[mid..]`.
///
/// # Safety
///
/// `mid` must not be greater than `self.deref().len()`.
///
/// # Panics
///
/// Implementations of this method may choose to perform a bounds check and
/// panic if `mid > self.deref().len()`. They may also panic for any other
/// reason. Since it is optional, callers must not rely on this behavior for
/// soundness.
#[must_use]
unsafe fn split_at_unchecked(self, mid: usize) -> (Self, Self);
}
/// A shorthand for [`SplitByteSlice`] and [`ByteSliceMut`].
pub trait SplitByteSliceMut: SplitByteSlice + ByteSliceMut {}
impl<B: SplitByteSlice + ByteSliceMut> SplitByteSliceMut for B {}
#[allow(clippy::missing_safety_doc)] // There's a `Safety` section on `into_byte_slice`.
/// A [`ByteSlice`] that conveys no ownership, and so can be converted into a
/// byte slice.
///
/// Some `ByteSlice` types (notably, the standard library's [`Ref`] type) convey
/// ownership, and so they cannot soundly be moved by-value into a byte slice
/// type (`&[u8]`). Some methods in this crate's API (such as [`Ref::into_ref`])
/// are only compatible with `ByteSlice` types without these ownership
/// semantics.
///
/// [`Ref`]: core::cell::Ref
pub unsafe trait IntoByteSlice<'a>: ByteSlice {
/// Coverts `self` into a `&[u8]`.
///
/// # Safety
///
/// The returned reference has the same address and length as `self.deref()`
/// and `self.deref_mut()`.
///
/// Note that, combined with the safety invariant on [`ByteSlice`], this
/// safety invariant implies that the returned reference is "stable" in the
/// sense described in the `ByteSlice` docs.
fn into_byte_slice(self) -> &'a [u8];
}
#[allow(clippy::missing_safety_doc)] // There's a `Safety` section on `into_byte_slice_mut`.
/// A [`ByteSliceMut`] that conveys no ownership, and so can be converted into a
/// mutable byte slice.
///
/// Some `ByteSliceMut` types (notably, the standard library's [`RefMut`] type)
/// convey ownership, and so they cannot soundly be moved by-value into a byte
/// slice type (`&mut [u8]`). Some methods in this crate's API (such as
/// [`Ref::into_mut`]) are only compatible with `ByteSliceMut` types without
/// these ownership semantics.
///
/// [`RefMut`]: core::cell::RefMut
pub unsafe trait IntoByteSliceMut<'a>: IntoByteSlice<'a> + ByteSliceMut {
/// Coverts `self` into a `&mut [u8]`.
///
/// # Safety
///
/// The returned reference has the same address and length as `self.deref()`
/// and `self.deref_mut()`.
///
/// Note that, combined with the safety invariant on [`ByteSlice`], this
/// safety invariant implies that the returned reference is "stable" in the
/// sense described in the `ByteSlice` docs.
fn into_byte_slice_mut(self) -> &'a mut [u8];
}
// FIXME(#429): Add a "SAFETY" comment and remove this `allow`.
#[allow(clippy::undocumented_unsafe_blocks)]
unsafe impl ByteSlice for &[u8] {}
// FIXME(#429): Add a "SAFETY" comment and remove this `allow`.
#[allow(clippy::undocumented_unsafe_blocks)]
unsafe impl CopyableByteSlice for &[u8] {}
// FIXME(#429): Add a "SAFETY" comment and remove this `allow`.
#[allow(clippy::undocumented_unsafe_blocks)]
unsafe impl CloneableByteSlice for &[u8] {}
// SAFETY: This delegates to `polyfills:split_at_unchecked`, which is documented
// to correctly split `self` into two slices at the given `mid` point.
unsafe impl SplitByteSlice for &[u8] {
#[inline]
unsafe fn split_at_unchecked(self, mid: usize) -> (Self, Self) {
// SAFETY: By contract on caller, `mid` is not greater than
// `self.len()`.
#[allow(clippy::multiple_unsafe_ops_per_block)]
unsafe {
(<[u8]>::get_unchecked(self, ..mid), <[u8]>::get_unchecked(self, mid..))
}
}
}
// SAFETY: See inline.
unsafe impl<'a> IntoByteSlice<'a> for &'a [u8] {
#[inline(always)]
fn into_byte_slice(self) -> &'a [u8] {
// SAFETY: It would be patently insane to implement `<Deref for
// &[u8]>::deref` as anything other than `fn deref(&self) -> &[u8] {
// *self }`. Assuming this holds, then `self` is stable as required by
// `into_byte_slice`.
self
}
}
// FIXME(#429): Add a "SAFETY" comment and remove this `allow`.
#[allow(clippy::undocumented_unsafe_blocks)]
unsafe impl ByteSlice for &mut [u8] {}
// SAFETY: This delegates to `polyfills:split_at_mut_unchecked`, which is
// documented to correctly split `self` into two slices at the given `mid`
// point.
unsafe impl SplitByteSlice for &mut [u8] {
#[inline]
unsafe fn split_at_unchecked(self, mid: usize) -> (Self, Self) {
use core::slice::from_raw_parts_mut;
// `l_ptr` is non-null, because `self` is non-null, by invariant on
// `&mut [u8]`.
let l_ptr = self.as_mut_ptr();
// SAFETY: By contract on caller, `mid` is not greater than
// `self.len()`.
let r_ptr = unsafe { l_ptr.add(mid) };
let l_len = mid;
// SAFETY: By contract on caller, `mid` is not greater than
// `self.len()`.
//
// FIXME(#67): Remove this allow. See NumExt for more details.
#[allow(unstable_name_collisions)]
let r_len = unsafe { self.len().unchecked_sub(mid) };
// SAFETY: These invocations of `from_raw_parts_mut` satisfy its
// documented safety preconditions [1]:
// - The data `l_ptr` and `r_ptr` are valid for both reads and writes of
// `l_len` and `r_len` bytes, respectively, and they are trivially
// aligned. In particular:
// - The entire memory range of each slice is contained within a
// single allocated object, since `l_ptr` and `r_ptr` are both
// derived from within the address range of `self`.
// - Both `l_ptr` and `r_ptr` are non-null and trivially aligned.
// `self` is non-null by invariant on `&mut [u8]`, and the
// operations that derive `l_ptr` and `r_ptr` from `self` do not
// nullify either pointer.
// - The data `l_ptr` and `r_ptr` point to `l_len` and `r_len`,
// respectively, consecutive properly initialized values of type `u8`.
// This is true for `self` by invariant on `&mut [u8]`, and remains
// true for these two sub-slices of `self`.
// - The memory referenced by the returned slice cannot be accessed
// through any other pointer (not derived from the return value) for
// the duration of lifetime `'a``, because:
// - `split_at_unchecked` consumes `self` (which is not `Copy`),
// - `split_at_unchecked` does not exfiltrate any references to this
// memory, besides those references returned below,
// - the returned slices are non-overlapping.
// - The individual sizes of the sub-slices of `self` are no larger than
// `isize::MAX`, because their combined sizes are no larger than
// `isize::MAX`, by invariant on `self`.
//
// [1] https://doc.rust-lang.org/std/slice/fn.from_raw_parts_mut.html#safety
#[allow(clippy::multiple_unsafe_ops_per_block)]
unsafe {
(from_raw_parts_mut(l_ptr, l_len), from_raw_parts_mut(r_ptr, r_len))
}
}
}
// SAFETY: See inline.
unsafe impl<'a> IntoByteSlice<'a> for &'a mut [u8] {
#[inline(always)]
fn into_byte_slice(self) -> &'a [u8] {
// SAFETY: It would be patently insane to implement `<Deref for &mut
// [u8]>::deref` as anything other than `fn deref(&self) -> &[u8] {
// *self }`. Assuming this holds, then `self` is stable as required by
// `into_byte_slice`.
self
}
}
// SAFETY: See inline.
unsafe impl<'a> IntoByteSliceMut<'a> for &'a mut [u8] {
#[inline(always)]
fn into_byte_slice_mut(self) -> &'a mut [u8] {
// SAFETY: It would be patently insane to implement `<DerefMut for &mut
// [u8]>::deref` as anything other than `fn deref_mut(&mut self) -> &mut
// [u8] { *self }`. Assuming this holds, then `self` is stable as
// required by `into_byte_slice_mut`.
self
}
}
// FIXME(#429): Add a "SAFETY" comment and remove this `allow`.
#[allow(clippy::undocumented_unsafe_blocks)]
unsafe impl ByteSlice for cell::Ref<'_, [u8]> {}
// SAFETY: This delegates to stdlib implementation of `Ref::map_split`, which is
// assumed to be correct, and `SplitByteSlice::split_at_unchecked`, which is
// documented to correctly split `self` into two slices at the given `mid`
// point.
unsafe impl SplitByteSlice for cell::Ref<'_, [u8]> {
#[inline]
unsafe fn split_at_unchecked(self, mid: usize) -> (Self, Self) {
cell::Ref::map_split(self, |slice|
// SAFETY: By precondition on caller, `mid` is not greater than
// `slice.len()`.
unsafe {
SplitByteSlice::split_at_unchecked(slice, mid)
})
}
}
// FIXME(#429): Add a "SAFETY" comment and remove this `allow`.
#[allow(clippy::undocumented_unsafe_blocks)]
unsafe impl ByteSlice for cell::RefMut<'_, [u8]> {}
// SAFETY: This delegates to stdlib implementation of `RefMut::map_split`, which
// is assumed to be correct, and `SplitByteSlice::split_at_unchecked`, which is
// documented to correctly split `self` into two slices at the given `mid`
// point.
unsafe impl SplitByteSlice for cell::RefMut<'_, [u8]> {
#[inline]
unsafe fn split_at_unchecked(self, mid: usize) -> (Self, Self) {
cell::RefMut::map_split(self, |slice|
// SAFETY: By precondition on caller, `mid` is not greater than
// `slice.len()`
unsafe {
SplitByteSlice::split_at_unchecked(slice, mid)
})
}
}
#[cfg(kani)]
mod proofs {
use super::*;
fn any_vec() -> Vec<u8> {
let len = kani::any();
kani::assume(len <= crate::DstLayout::MAX_SIZE);
vec![0u8; len]
}
#[kani::proof]
fn prove_split_at_unchecked() {
let v = any_vec();
let slc = v.as_slice();
let mid = kani::any();
kani::assume(mid <= slc.len());
let (l, r) = unsafe { slc.split_at_unchecked(mid) };
assert_eq!(l.len() + r.len(), slc.len());
let slc: *const _ = slc;
let l: *const _ = l;
let r: *const _ = r;
assert_eq!(slc.cast::<u8>(), l.cast::<u8>());
assert_eq!(unsafe { slc.cast::<u8>().add(mid) }, r.cast::<u8>());
let mut v = any_vec();
let slc = v.as_mut_slice();
let len = slc.len();
let mid = kani::any();
kani::assume(mid <= slc.len());
let (l, r) = unsafe { slc.split_at_unchecked(mid) };
assert_eq!(l.len() + r.len(), len);
let l: *mut _ = l;
let r: *mut _ = r;
let slc: *mut _ = slc;
assert_eq!(slc.cast::<u8>(), l.cast::<u8>());
assert_eq!(unsafe { slc.cast::<u8>().add(mid) }, r.cast::<u8>());
}
}
#[cfg(test)]
mod tests {
use core::cell::RefCell;
use super::*;
#[test]
fn test_ref_split_at_unchecked() {
let cell = RefCell::new([1, 2, 3, 4]);
let borrow = cell.borrow();
let slice_ref: cell::Ref<'_, [u8]> = cell::Ref::map(borrow, |a| &a[..]);
// SAFETY: 2 is within bounds of [1, 2, 3, 4]
let (l, r) = unsafe { slice_ref.split_at_unchecked(2) };
assert_eq!(*l, [1, 2]);
assert_eq!(*r, [3, 4]);
}
#[test]
fn test_ref_mut_split_at_unchecked() {
let cell = RefCell::new([1, 2, 3, 4]);
let borrow_mut = cell.borrow_mut();
let slice_ref_mut: cell::RefMut<'_, [u8]> = cell::RefMut::map(borrow_mut, |a| &mut a[..]);
// SAFETY: 2 is within bounds of [1, 2, 3, 4]
let (l, r) = unsafe { slice_ref_mut.split_at_unchecked(2) };
assert_eq!(*l, [1, 2]);
assert_eq!(*r, [3, 4]);
}
}
File diff suppressed because it is too large Load Diff
+281
View File
@@ -0,0 +1,281 @@
// SPDX-License-Identifier: BSD-2-Clause OR Apache-2.0 OR MIT
//
// Copyright 2024 The Fuchsia Authors
//
// Licensed under the 2-Clause BSD License <LICENSE-BSD or
// https://opensource.org/license/bsd-2-clause>, 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.
//! Deprecated items. These are kept separate so that they don't clutter up
//! other modules.
use super::*;
impl<B, T> Ref<B, T>
where
B: ByteSlice,
T: KnownLayout + Immutable + ?Sized,
{
#[deprecated(since = "0.8.0", note = "renamed to `Ref::from_bytes`")]
#[doc(hidden)]
#[must_use = "has no side effects"]
#[inline(always)]
pub fn new(bytes: B) -> Option<Ref<B, T>> {
Self::from_bytes(bytes).ok()
}
}
impl<B, T> Ref<B, T>
where
B: SplitByteSlice,
T: KnownLayout + Immutable + ?Sized,
{
#[deprecated(since = "0.8.0", note = "renamed to `Ref::from_prefix`")]
#[doc(hidden)]
#[must_use = "has no side effects"]
#[inline(always)]
pub fn new_from_prefix(bytes: B) -> Option<(Ref<B, T>, B)> {
Self::from_prefix(bytes).ok()
}
}
impl<B, T> Ref<B, T>
where
B: SplitByteSlice,
T: KnownLayout + Immutable + ?Sized,
{
#[deprecated(since = "0.8.0", note = "renamed to `Ref::from_suffix`")]
#[doc(hidden)]
#[must_use = "has no side effects"]
#[inline(always)]
pub fn new_from_suffix(bytes: B) -> Option<(B, Ref<B, T>)> {
Self::from_suffix(bytes).ok()
}
}
impl<B, T> Ref<B, T>
where
B: ByteSlice,
T: Unaligned + KnownLayout + Immutable + ?Sized,
{
#[deprecated(
since = "0.8.0",
note = "use `Ref::from_bytes`; for `T: Unaligned`, the returned `CastError` implements `Into<SizeError>`"
)]
#[doc(hidden)]
#[must_use = "has no side effects"]
#[inline(always)]
pub fn new_unaligned(bytes: B) -> Option<Ref<B, T>> {
Self::from_bytes(bytes).ok()
}
}
impl<B, T> Ref<B, T>
where
B: SplitByteSlice,
T: Unaligned + KnownLayout + Immutable + ?Sized,
{
#[deprecated(
since = "0.8.0",
note = "use `Ref::from_prefix`; for `T: Unaligned`, the returned `CastError` implements `Into<SizeError>`"
)]
#[doc(hidden)]
#[must_use = "has no side effects"]
#[inline(always)]
pub fn new_unaligned_from_prefix(bytes: B) -> Option<(Ref<B, T>, B)> {
Self::from_prefix(bytes).ok()
}
}
impl<B, T> Ref<B, T>
where
B: SplitByteSlice,
T: Unaligned + KnownLayout + Immutable + ?Sized,
{
#[deprecated(
since = "0.8.0",
note = "use `Ref::from_suffix`; for `T: Unaligned`, the returned `CastError` implements `Into<SizeError>`"
)]
#[doc(hidden)]
#[must_use = "has no side effects"]
#[inline(always)]
pub fn new_unaligned_from_suffix(bytes: B) -> Option<(B, Ref<B, T>)> {
Self::from_suffix(bytes).ok()
}
}
impl<B, T> Ref<B, [T]>
where
B: ByteSlice,
T: Immutable,
{
#[deprecated(since = "0.8.0", note = "`Ref::from_bytes` now supports slices")]
#[doc(hidden)]
#[inline(always)]
pub fn new_slice(bytes: B) -> Option<Ref<B, [T]>> {
Self::from_bytes(bytes).ok()
}
}
impl<B, T> Ref<B, [T]>
where
B: ByteSlice,
T: Unaligned + Immutable,
{
#[deprecated(
since = "0.8.0",
note = "`Ref::from_bytes` now supports slices; for `T: Unaligned`, the returned `CastError` implements `Into<SizeError>`"
)]
#[doc(hidden)]
#[inline(always)]
pub fn new_slice_unaligned(bytes: B) -> Option<Ref<B, [T]>> {
Ref::from_bytes(bytes).ok()
}
}
impl<'a, B, T> Ref<B, [T]>
where
B: 'a + IntoByteSlice<'a>,
T: FromBytes + Immutable,
{
#[deprecated(since = "0.8.0", note = "`Ref::into_ref` now supports slices")]
#[doc(hidden)]
#[inline(always)]
pub fn into_slice(self) -> &'a [T] {
Ref::into_ref(self)
}
}
impl<'a, B, T> Ref<B, [T]>
where
B: 'a + IntoByteSliceMut<'a>,
T: FromBytes + IntoBytes + Immutable,
{
#[deprecated(since = "0.8.0", note = "`Ref::into_mut` now supports slices")]
#[doc(hidden)]
#[inline(always)]
pub fn into_mut_slice(self) -> &'a mut [T] {
Ref::into_mut(self)
}
}
impl<B, T> Ref<B, [T]>
where
B: SplitByteSlice,
T: Immutable,
{
#[deprecated(since = "0.8.0", note = "replaced by `Ref::from_prefix_with_elems`")]
#[must_use = "has no side effects"]
#[doc(hidden)]
#[inline(always)]
pub fn new_slice_from_prefix(bytes: B, count: usize) -> Option<(Ref<B, [T]>, B)> {
Ref::from_prefix_with_elems(bytes, count).ok()
}
#[deprecated(since = "0.8.0", note = "replaced by `Ref::from_suffix_with_elems`")]
#[must_use = "has no side effects"]
#[doc(hidden)]
#[inline(always)]
pub fn new_slice_from_suffix(bytes: B, count: usize) -> Option<(B, Ref<B, [T]>)> {
Ref::from_suffix_with_elems(bytes, count).ok()
}
}
impl<B, T> Ref<B, [T]>
where
B: SplitByteSlice,
T: Unaligned + Immutable,
{
#[deprecated(
since = "0.8.0",
note = "use `Ref::from_prefix_with_elems`; for `T: Unaligned`, the returned `CastError` implements `Into<SizeError>`"
)]
#[doc(hidden)]
#[must_use = "has no side effects"]
#[inline(always)]
pub fn new_slice_unaligned_from_prefix(bytes: B, count: usize) -> Option<(Ref<B, [T]>, B)> {
Ref::from_prefix_with_elems(bytes, count).ok()
}
#[deprecated(
since = "0.8.0",
note = "use `Ref::from_suffix_with_elems`; for `T: Unaligned`, the returned `CastError` implements `Into<SizeError>`"
)]
#[doc(hidden)]
#[must_use = "has no side effects"]
#[inline(always)]
pub fn new_slice_unaligned_from_suffix(bytes: B, count: usize) -> Option<(B, Ref<B, [T]>)> {
Ref::from_suffix_with_elems(bytes, count).ok()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[allow(deprecated)]
fn test_deprecated_ref_methods() {
let bytes = &[0u8; 1][..];
let bytes_slice = &[0u8; 4][..];
let r: Option<Ref<&[u8], u8>> = Ref::new(bytes);
assert!(r.is_some());
let r: Option<(Ref<&[u8], u8>, &[u8])> = Ref::new_from_prefix(bytes);
assert!(r.is_some());
let r: Option<(&[u8], Ref<&[u8], u8>)> = Ref::new_from_suffix(bytes);
assert!(r.is_some());
let r: Option<Ref<&[u8], u8>> = Ref::new_unaligned(bytes);
assert!(r.is_some());
let r: Option<(Ref<&[u8], u8>, &[u8])> = Ref::new_unaligned_from_prefix(bytes);
assert!(r.is_some());
let r: Option<(&[u8], Ref<&[u8], u8>)> = Ref::new_unaligned_from_suffix(bytes);
assert!(r.is_some());
let r: Option<Ref<&[u8], [u8]>> = Ref::new_slice(bytes_slice);
assert!(r.is_some());
let r: Option<Ref<&[u8], [u8]>> = Ref::new_slice_unaligned(bytes_slice);
assert!(r.is_some());
let r: Option<(Ref<&[u8], [u8]>, &[u8])> = Ref::new_slice_from_prefix(bytes_slice, 1);
assert!(r.is_some());
let r: Option<(&[u8], Ref<&[u8], [u8]>)> = Ref::new_slice_from_suffix(bytes_slice, 1);
assert!(r.is_some());
let r: Option<(Ref<&[u8], [u8]>, &[u8])> =
Ref::new_slice_unaligned_from_prefix(bytes_slice, 1);
assert!(r.is_some());
let r: Option<(&[u8], Ref<&[u8], [u8]>)> =
Ref::new_slice_unaligned_from_suffix(bytes_slice, 1);
assert!(r.is_some());
}
#[test]
#[allow(deprecated)]
fn test_deprecated_into_slice() {
let bytes = &[0u8; 4][..];
let r: Ref<&[u8], [u8]> = Ref::from_bytes(bytes).unwrap();
let slice: &[u8] = r.into_slice();
assert_eq!(slice.len(), 4);
}
#[test]
#[allow(deprecated)]
fn test_deprecated_into_mut_slice() {
let mut bytes = [0u8; 4];
let r: Ref<&mut [u8], [u8]> = Ref::from_bytes(&mut bytes[..]).unwrap();
let slice: &mut [u8] = r.into_mut_slice();
assert_eq!(slice.len(), 4);
}
}
+170
View File
@@ -0,0 +1,170 @@
// SPDX-License-Identifier: BSD-2-Clause OR Apache-2.0 OR MIT
//
// Copyright 2025 The Fuchsia Authors
//
// Licensed under the 2-Clause BSD License <LICENSE-BSD or
// https://opensource.org/license/bsd-2-clause>, 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.
#![cfg(feature = "derive")] // Required for derives on `SliceDst`
#![allow(dead_code, missing_docs, missing_debug_implementations, missing_copy_implementations)]
//! Our UI test framework, built on the `trybuild` crate, does not support
//! testing for post-monomorphization errors. Instead, we use doctests, which
//! are able to test for post-monomorphization errors.
use crate::*;
#[derive(KnownLayout, FromBytes, IntoBytes, Immutable)]
#[repr(C)]
pub struct SliceDst<T, U> {
pub t: T,
pub u: [U],
}
#[allow(clippy::must_use_candidate, clippy::missing_inline_in_public_items, clippy::todo)]
impl<T: FromBytes + IntoBytes, U: FromBytes + IntoBytes> SliceDst<T, U> {
pub fn new() -> &'static SliceDst<T, U> {
todo!()
}
pub fn new_mut() -> &'static mut SliceDst<T, U> {
todo!()
}
}
/// We require that the alignment of the destination type is not larger than the
/// alignment of the source type.
///
/// ```compile_fail,E0080
/// let increase_alignment: &u16 = zerocopy::transmute_ref!(&[0u8; 2]);
/// ```
///
/// ```compile_fail,E0080
/// let mut src = [0u8; 2];
/// let increase_alignment: &mut u16 = zerocopy::transmute_mut!(&mut src);
/// ```
///
/// ```compile_fail,E0080
/// let increase_alignment: &u16 = zerocopy::try_transmute_ref!(&[0u8; 2]).unwrap();
/// ```
///
/// ```compile_fail,E0080
/// let mut src = [0u8; 2];
/// let increase_alignment: &mut u16 = zerocopy::try_transmute_mut!(&mut src).unwrap();
/// ```
enum TransmuteRefMutAlignmentIncrease {}
/// We require that the size of the destination type is not larger than the size
/// of the source type.
///
/// ```compile_fail,E0080
/// let increase_size: &[u8; 2] = zerocopy::transmute_ref!(&0u8);
/// ```
///
/// ```compile_fail,E0080
/// let mut src = 0u8;
/// let increase_size: &mut [u8; 2] = zerocopy::transmute_mut!(&mut src);
/// ```
///
/// ```compile_fail,E0080
/// let increase_size: &[u8; 2] = zerocopy::try_transmute_ref!(&0u8).unwrap();
/// ```
///
/// ```compile_fail,E0080
/// let mut src = 0u8;
/// let increase_size: &mut [u8; 2] = zerocopy::try_transmute_mut!(&mut src).unwrap();
/// ```
enum TransmuteRefMutSizeIncrease {}
/// We require that the size of the destination type is not smaller than the
/// size of the source type.
///
/// ```compile_fail,E0080
/// let decrease_size: &u8 = zerocopy::transmute_ref!(&[0u8; 2]);
/// ```
///
/// ```compile_fail,E0080
/// let mut src = [0u8; 2];
/// let decrease_size: &mut u8 = zerocopy::transmute_mut!(&mut src);
/// ```
///
/// ```compile_fail,E0080
/// let decrease_size: &u8 = zerocopy::try_transmute_ref!(&[0u8; 2]).unwrap();
/// ```
///
/// ```compile_fail,E0080
/// let mut src = [0u8; 2];
/// let decrease_size: &mut u8 = zerocopy::try_transmute_mut!(&mut src).unwrap();
/// ```
enum TransmuteRefMutSizeDecrease {}
/// It's not possible in the general case to increase the trailing slice offset
/// during a reference transmutation - some pointer metadata values would not be
/// supportable, and so such a transmutation would be fallible.
///
/// ```compile_fail,E0080
/// use zerocopy::doctests::SliceDst;
/// let src: &SliceDst<u8, u8> = SliceDst::new();
/// let increase_offset: &SliceDst<[u8; 2], u8> = zerocopy::transmute_ref!(src);
/// ```
///
/// ```compile_fail,E0080
/// use zerocopy::doctests::SliceDst;
/// let src: &mut SliceDst<u8, u8> = SliceDst::new_mut();
/// let increase_offset: &mut SliceDst<[u8; 2], u8> = zerocopy::transmute_mut!(src);
/// ```
enum TransmuteRefMutDstOffsetIncrease {}
/// Reference transmutes are not possible when the difference between the source
/// and destination types' trailing slice offsets is not a multiple of the
/// destination type's trailing slice element size.
///
/// ```compile_fail,E0080
/// use zerocopy::doctests::SliceDst;
/// let src: &SliceDst<[u8; 3], [u8; 2]> = SliceDst::new();
/// let _: &SliceDst<[u8; 2], [u8; 2]> = zerocopy::transmute_ref!(src);
/// ```
///
/// ```compile_fail,E0080
/// use zerocopy::doctests::SliceDst;
/// let src: &mut SliceDst<[u8; 3], [u8; 2]> = SliceDst::new_mut();
/// let _: &mut SliceDst<[u8; 2], [u8; 2]> = zerocopy::transmute_mut!(src);
/// ```
enum TransmuteRefMutDstOffsetNotMultiple {}
/// Reference transmutes are not possible when the source's trailing slice
/// element size is not a multiple of the destination's.
///
/// ```compile_fail,E0080
/// use zerocopy::doctests::SliceDst;
/// let src: &SliceDst<(), [u8; 3]> = SliceDst::new();
/// let _: &SliceDst<(), [u8; 2]> = zerocopy::transmute_ref!(src);
/// ```
///
/// ```compile_fail,E0080
/// use zerocopy::doctests::SliceDst;
/// let src: &mut SliceDst<(), [u8; 3]> = SliceDst::new_mut();
/// let _: &mut SliceDst<(), [u8; 2]> = zerocopy::transmute_mut!(src);
/// ```
enum TransmuteRefMutDstElemSizeNotMultiple {}
/// ```compile_fail,E0277
/// use zerocopy::*;
///
/// #[derive(FromBytes, IntoBytes, Unaligned)]
/// #[repr(transparent)]
/// struct Foo<T>(T);
///
/// const _: () = unsafe {
/// impl_or_verify!(T => TryFromBytes for Foo<T>);
/// impl_or_verify!(T => FromZeros for Foo<T>);
/// impl_or_verify!(T => FromBytes for Foo<T>);
/// impl_or_verify!(T => IntoBytes for Foo<T>);
/// impl_or_verify!(T => Unaligned for Foo<T>);
/// };
/// ```
enum InvalidImplOrVerify {}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+754
View File
@@ -0,0 +1,754 @@
// 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) }
})
}
}
impl<'a, T, const N: usize> PtrInner<'a, [T; N]> {
/// Casts this pointer-to-array into a slice.
///
/// # Safety
///
/// Callers may assume that the returned `PtrInner` references the same
/// address and length as `self`.
#[allow(clippy::wrong_self_convention)]
#[inline]
#[must_use]
pub fn as_slice(self) -> PtrInner<'a, [T]> {
let start = self.as_non_null().cast::<T>().as_ptr();
let slice = core::ptr::slice_from_raw_parts_mut(start, N);
// SAFETY: `slice` is not null, because it is derived from `start`
// which is non-null.
let slice = unsafe { NonNull::new_unchecked(slice) };
// SAFETY: Lemma: In the following safety arguments, note that `slice`
// is derived from `self` in two steps: first, by casting `self: [T; N]`
// to `start: T`, then by constructing a pointer to a slice starting at
// `start` of length `N`. As a result, `slice` references exactly the
// same allocation as `self`, if any.
//
// 0. By the above lemma, if `slice`'s referent is not zero sized, then
// `slice` has the same referent as `self`. By invariant on `self`,
// this referent is entirely contained within some allocation, `A`.
// Because `slice` was constructed using provenance-preserving
// operations, it has provenance for its entire referent.
// 1. By the above lemma, if `slice`'s referent is not zero sized, then
// `A` is guaranteed to live for at least `'a`, because it is derived
// from the same allocation as `self`, which, by invariant on
// `PtrInner`, lives for at least `'a`.
unsafe { PtrInner::new(slice) }
}
}
impl<'a> PtrInner<'a, [u8]> {
/// Attempts to cast `self` to a `U` using the given cast type.
///
/// If `U` is a slice DST and pointer metadata (`meta`) is provided, then
/// the cast will only succeed if it would produce an object with the given
/// metadata.
///
/// Returns `None` if the resulting `U` would be invalidly-aligned, if no
/// `U` can fit in `self`, or if the provided pointer metadata describes an
/// invalid instance of `U`. On success, returns a pointer to the
/// largest-possible `U` which fits in `self`.
///
/// # Safety
///
/// The caller may assume that this implementation is correct, and may rely
/// on that assumption for the soundness of their code. In particular, the
/// caller may assume that, if `try_cast_into` returns `Some((ptr,
/// remainder))`, then `ptr` and `remainder` refer to non-overlapping byte
/// ranges within `self`, and that `ptr` and `remainder` entirely cover
/// `self`. Finally:
/// - If this is a prefix cast, `ptr` has the same address as `self`.
/// - If this is a suffix cast, `remainder` has the same address as `self`.
#[inline]
pub fn try_cast_into<U>(
self,
cast_type: CastType,
meta: Option<U::PointerMetadata>,
) -> Result<(PtrInner<'a, U>, PtrInner<'a, [u8]>), CastError<Self, U>>
where
U: 'a + ?Sized + KnownLayout,
{
// PANICS: By invariant, the byte range addressed by
// `self.as_non_null()` does not wrap around the address space. This
// implies that the sum of the address (represented as a `usize`) and
// length do not overflow `usize`, as required by
// `validate_cast_and_convert_metadata`. Thus, this call to
// `validate_cast_and_convert_metadata` will only panic if `U` is a DST
// whose trailing slice element is zero-sized.
let maybe_metadata = MetadataOf::<U>::validate_cast_and_convert_metadata(
AsAddress::addr(self.as_ptr()),
self.meta(),
cast_type,
meta,
);
let (elems, split_at) = match maybe_metadata {
Ok((elems, split_at)) => (elems, split_at),
Err(MetadataCastError::Alignment) => {
// SAFETY: Since `validate_cast_and_convert_metadata` returned
// an alignment error, `U` must have an alignment requirement
// greater than one.
let err = unsafe { AlignmentError::<_, U>::new_unchecked(self) };
return Err(CastError::Alignment(err));
}
Err(MetadataCastError::Size) => return Err(CastError::Size(SizeError::new(self))),
};
// SAFETY: `validate_cast_and_convert_metadata` promises to return
// `split_at <= self.meta()`.
//
// Lemma 0: `l_slice` and `r_slice` are non-overlapping. Proof: By
// contract on `PtrInner::split_at_unchecked`, the produced `PtrInner`s
// are always non-overlapping if `self` is a `[T]`; here it is a `[u8]`.
let (l_slice, r_slice) = unsafe { self.split_at_unchecked(split_at) };
let (target, remainder) = match cast_type {
CastType::Prefix => (l_slice, r_slice),
CastType::Suffix => (r_slice, l_slice),
};
let base = target.as_non_null().cast::<u8>();
let ptr = U::raw_from_ptr_len(base, elems.get());
// SAFETY:
// 0. By invariant, if `target`'s referent is not zero sized, then
// `target` has provenance valid for some Rust allocation, `A`.
// Because `ptr` is derived from `target` via provenance-preserving
// operations, `ptr` will also have provenance valid for its entire
// referent.
// 1. `validate_cast_and_convert_metadata` promises that the object
// described by `elems` and `split_at` lives at a byte range which is
// a subset of the input byte range. Thus, by invariant, if
// `target`'s referent is not zero sized, then `target` refers to an
// allocation which is guaranteed to live for at least `'a`, and thus
// so does `ptr`.
Ok((unsafe { PtrInner::new(ptr) }, remainder))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::*;
#[test]
fn test_meta() {
let arr = [1; 16];
let dst = <[u8]>::ref_from_bytes(&arr[..]).unwrap();
let ptr = PtrInner::from_ref(dst);
assert_eq!(ptr.meta().get(), 16);
// SAFETY: 8 is less than 16
let ptr = unsafe { ptr.with_meta(8) };
assert_eq!(ptr.meta().get(), 8);
}
#[test]
fn test_split_at() {
fn test_split_at<const OFFSET: usize, const BUFFER_SIZE: usize>() {
#[derive(FromBytes, KnownLayout, SplitAt, Immutable)]
#[repr(C)]
struct SliceDst<const OFFSET: usize> {
prefix: [u8; OFFSET],
trailing: [u8],
}
let n: usize = BUFFER_SIZE - OFFSET;
let arr = [1; BUFFER_SIZE];
let dst = SliceDst::<OFFSET>::ref_from_bytes(&arr[..]).unwrap();
let ptr = PtrInner::from_ref(dst);
for i in 0..=n {
assert_eq!(ptr.meta().get(), n);
// SAFETY: `i` is in bounds by construction.
let i = unsafe { MetadataOf::new_unchecked(i) };
// SAFETY: `i` is in bounds by construction.
let (l, r) = unsafe { ptr.split_at_unchecked(i) };
// SAFETY: Points to a valid value by construction.
#[allow(clippy::undocumented_unsafe_blocks, clippy::as_conversions)]
// Clippy false positive
let l_sum: usize = l
.trailing_slice()
.iter()
.map(
#[inline(always)]
|ptr| unsafe { core::ptr::read_unaligned(ptr.as_ptr()) } as usize,
)
.sum();
// SAFETY: Points to a valid value by construction.
#[allow(clippy::undocumented_unsafe_blocks, clippy::as_conversions)]
// Clippy false positive
let r_sum: usize = r
.iter()
.map(
#[inline(always)]
|ptr| unsafe { core::ptr::read_unaligned(ptr.as_ptr()) } as usize,
)
.sum();
assert_eq!(l_sum, i.get());
assert_eq!(r_sum, n - i.get());
assert_eq!(l_sum + r_sum, n);
}
}
test_split_at::<0, 16>();
test_split_at::<1, 17>();
test_split_at::<2, 18>();
}
#[test]
fn test_trailing_slice() {
fn test_trailing_slice<const OFFSET: usize, const BUFFER_SIZE: usize>() {
#[derive(FromBytes, KnownLayout, SplitAt, Immutable)]
#[repr(C)]
struct SliceDst<const OFFSET: usize> {
prefix: [u8; OFFSET],
trailing: [u8],
}
let n: usize = BUFFER_SIZE - OFFSET;
let arr = [1; BUFFER_SIZE];
let dst = SliceDst::<OFFSET>::ref_from_bytes(&arr[..]).unwrap();
let ptr = PtrInner::from_ref(dst);
assert_eq!(ptr.meta().get(), n);
let trailing = ptr.trailing_slice();
assert_eq!(trailing.meta().get(), n);
assert_eq!(
// SAFETY: We assume this to be sound for the sake of this test,
// which will fail, here, in miri, if the safety precondition of
// `offset_of` is not satisfied.
unsafe {
#[allow(clippy::as_conversions)]
let offset = (trailing.as_ptr() as *mut u8).offset_from(ptr.as_ptr() as *mut _);
offset
},
isize::try_from(OFFSET).unwrap(),
);
// SAFETY: Points to a valid value by construction.
#[allow(clippy::undocumented_unsafe_blocks, clippy::as_conversions)]
// Clippy false positive
let trailing: usize = trailing
.iter()
.map(|ptr| unsafe { core::ptr::read_unaligned(ptr.as_ptr()) } as usize)
.sum();
assert_eq!(trailing, n);
}
test_trailing_slice::<0, 16>();
test_trailing_slice::<1, 17>();
test_trailing_slice::<2, 18>();
}
#[test]
fn test_ptr_inner_clone() {
let mut x = 0u8;
let p = PtrInner::from_mut(&mut x);
#[allow(clippy::clone_on_copy)]
let p2 = p.clone();
assert_eq!(p.as_non_null(), p2.as_non_null());
}
}
+298
View File
@@ -0,0 +1,298 @@
// 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.
#![allow(missing_copy_implementations, missing_debug_implementations, missing_docs)]
//! The parameterized invariants of a [`Ptr`][super::Ptr].
//!
//! Invariants are encoded as ([`Aliasing`], [`Alignment`], [`Validity`])
//! triples implementing the [`Invariants`] trait.
/// The invariants of a [`Ptr`][super::Ptr].
pub trait Invariants: Sealed {
type Aliasing: Aliasing;
type Alignment: Alignment;
type Validity: Validity;
}
impl<A: Aliasing, AA: Alignment, V: Validity> Invariants for (A, AA, V) {
type Aliasing = A;
type Alignment = AA;
type Validity = V;
}
/// The aliasing invariant of a [`Ptr`][super::Ptr].
///
/// All aliasing invariants must permit reading from the bytes of a pointer's
/// referent which are not covered by [`UnsafeCell`]s.
///
/// [`UnsafeCell`]: core::cell::UnsafeCell
pub trait Aliasing: Sealed {
/// Is `Self` [`Exclusive`]?
#[doc(hidden)]
const IS_EXCLUSIVE: bool;
}
/// The alignment invariant of a [`Ptr`][super::Ptr].
pub trait Alignment: Sealed {
#[doc(hidden)]
#[must_use]
fn read<T, I, R>(ptr: crate::Ptr<'_, T, I>) -> T
where
T: Copy + Read<I::Aliasing, R>,
I: Invariants<Alignment = Self, Validity = Valid>,
I::Aliasing: Reference;
}
/// The validity invariant of a [`Ptr`][super::Ptr].
///
/// # Safety
///
/// In this section, we will use `Ptr<T, V>` as a shorthand for `Ptr<T, I:
/// Invariants<Validity = V>>` for brevity.
///
/// Each `V: Validity` defines a set of bit values which may appear in the
/// referent of a `Ptr<T, V>`, denoted `S(T, V)`. Each `V: Validity`, in its
/// documentation, provides a definition of `S(T, V)` which must be valid for
/// all `T: ?Sized`. Any `V: Validity` must guarantee that this set is only a
/// function of the *bit validity* of the referent type, `T`, and not of any
/// other property of `T`. As a consequence, given `V: Validity`, `T`, and `U`
/// where `T` and `U` have the same bit validity, `S(V, T) = S(V, U)`.
///
/// It is guaranteed that the referent of any `ptr: Ptr<T, V>` is a member of
/// `S(T, V)`. Unsafe code must ensure that this guarantee will be upheld for
/// any existing `Ptr`s or any `Ptr`s that that code creates.
///
/// An important implication of this guarantee is that it restricts what
/// transmutes are sound, where "transmute" is used in this context to refer to
/// changing the referent type or validity invariant of a `Ptr`, as either
/// change may change the set of bit values permitted to appear in the referent.
/// In particular, the following are necessary (but not sufficient) conditions
/// in order for a transmute from `src: Ptr<T, V>` to `dst: Ptr<U, W>` to be
/// sound:
/// - If `S(T, V) = S(U, W)`, then no restrictions apply; otherwise,
/// - If `dst` permits mutation of its referent (e.g. via `Exclusive` aliasing
/// or interior mutation under `Shared` aliasing), then it must hold that
/// `S(T, V) ⊇ S(U, W)` - in other words, the transmute must not expand the
/// set of allowed referent bit patterns. A violation of this requirement
/// would permit using `dst` to write `x` where `x ∈ S(U, W)` but `x ∉ S(T,
/// V)`, which would violate the guarantee that `src`'s referent may only
/// contain values in `S(T, V)`.
/// - If the referent may be mutated without going through `dst` while `dst` is
/// live (e.g. via interior mutation on a `Shared`-aliased `Ptr` or `&`
/// reference), then it must hold that `S(T, V) ⊆ S(U, W)` - in other words,
/// the transmute must not shrink the set of allowed referent bit patterns. A
/// violation of this requirement would permit using `src` or another
/// mechanism (e.g. a `&` reference used to derive `src`) to write `x` where
/// `x ∈ S(T, V)` but `x ∉ S(U, W)`, which would violate the guarantee that
/// `dst`'s referent may only contain values in `S(U, W)`.
pub unsafe trait Validity: Sealed {
const KIND: ValidityKind;
}
pub enum ValidityKind {
Uninit,
AsInitialized,
Initialized,
Valid,
}
/// An [`Aliasing`] invariant which is either [`Shared`] or [`Exclusive`].
///
/// # Safety
///
/// Given `A: Reference`, callers may assume that either `A = Shared` or `A =
/// Exclusive`.
pub trait Reference: Aliasing + Sealed {}
/// The `Ptr<'a, T>` adheres to the aliasing rules of a `&'a T`.
///
/// The referent of a shared-aliased `Ptr` may be concurrently referenced by any
/// number of shared-aliased `Ptr` or `&T` references, or by any number of
/// `Ptr<U>` or `&U` references as permitted by `T`'s library safety invariants,
/// and may not be concurrently referenced by any exclusively-aliased `Ptr`s or
/// `&mut` references. The referent must not be mutated, except via
/// [`UnsafeCell`]s, and only when permitted by `T`'s library safety invariants.
///
/// [`UnsafeCell`]: core::cell::UnsafeCell
pub enum Shared {}
impl Aliasing for Shared {
const IS_EXCLUSIVE: bool = false;
}
impl Reference for Shared {}
/// The `Ptr<'a, T>` adheres to the aliasing rules of a `&'a mut T`.
///
/// The referent of an exclusively-aliased `Ptr` may not be concurrently
/// referenced by any other `Ptr`s or references, and may not be accessed (read
/// or written) other than via this `Ptr`.
pub enum Exclusive {}
impl Aliasing for Exclusive {
const IS_EXCLUSIVE: bool = true;
}
impl Reference for Exclusive {}
/// It is unknown whether the pointer is aligned.
pub enum Unaligned {}
impl Alignment for Unaligned {
#[inline(always)]
fn read<T, I, R>(ptr: crate::Ptr<'_, T, I>) -> T
where
T: Copy + Read<I::Aliasing, R>,
I: Invariants<Alignment = Self, Validity = Valid>,
I::Aliasing: Reference,
{
(*ptr.into_unalign().as_ref()).into_inner()
}
}
/// The referent is aligned: for `Ptr<T>`, the referent's address is a multiple
/// of the `T`'s alignment.
pub enum Aligned {}
impl Alignment for Aligned {
#[inline(always)]
fn read<T, I, R>(ptr: crate::Ptr<'_, T, I>) -> T
where
T: Copy + Read<I::Aliasing, R>,
I: Invariants<Alignment = Self, Validity = Valid>,
I::Aliasing: Reference,
{
*ptr.as_ref()
}
}
/// Any bit pattern is allowed in the `Ptr`'s referent, including uninitialized
/// bytes.
pub enum Uninit {}
// SAFETY: `Uninit`'s validity is well-defined for all `T: ?Sized`, and is not a
// function of any property of `T` other than its bit validity (in fact, it's
// not even a property of `T`'s bit validity, but this is more than we are
// required to uphold).
unsafe impl Validity for Uninit {
const KIND: ValidityKind = ValidityKind::Uninit;
}
/// The byte ranges initialized in `T` are also initialized in the referent of a
/// `Ptr<T>`.
///
/// Formally: uninitialized bytes may only be present in `Ptr<T>`'s referent
/// where they are guaranteed to be present in `T`. This is a dynamic property:
/// if, at a particular byte offset, a valid enum discriminant is set, the
/// subsequent bytes may only have uninitialized bytes as specified by the
/// corresponding enum.
///
/// Formally, given `len = size_of_val_raw(ptr)`, at every byte offset, `b`, in
/// the range `[0, len)`:
/// - If, in any instance `t: T` of length `len`, the byte at offset `b` in `t`
/// is initialized, then the byte at offset `b` within `*ptr` must be
/// initialized.
/// - Let `c` be the contents of the byte range `[0, b)` in `*ptr`. Let `S` be
/// the subset of valid instances of `T` of length `len` which contain `c` in
/// the offset range `[0, b)`. If, in any instance of `t: T` in `S`, the byte
/// at offset `b` in `t` is initialized, then the byte at offset `b` in `*ptr`
/// must be initialized.
///
/// Pragmatically, this means that if `*ptr` is guaranteed to contain an enum
/// type at a particular offset, and the enum discriminant stored in `*ptr`
/// corresponds to a valid variant of that enum type, then it is guaranteed
/// that the appropriate bytes of `*ptr` are initialized as defined by that
/// variant's bit validity (although note that the variant may contain another
/// enum type, in which case the same rules apply depending on the state of
/// its discriminant, and so on recursively).
pub enum AsInitialized {}
// SAFETY: `AsInitialized`'s validity is well-defined for all `T: ?Sized`, and
// is not a function of any property of `T` other than its bit validity.
unsafe impl Validity for AsInitialized {
const KIND: ValidityKind = ValidityKind::AsInitialized;
}
/// The byte ranges in the referent are fully initialized. In other words, if
/// the referent is `N` bytes long, then it contains a bit-valid `[u8; N]`.
pub enum Initialized {}
// SAFETY: `Initialized`'s validity is well-defined for all `T: ?Sized`, and is
// not a function of any property of `T` other than its bit validity (in fact,
// it's not even a property of `T`'s bit validity, but this is more than we are
// required to uphold).
unsafe impl Validity for Initialized {
const KIND: ValidityKind = ValidityKind::Initialized;
}
/// The referent of a `Ptr<T>` is valid for `T`, upholding bit validity and any
/// library safety invariants.
pub enum Valid {}
// SAFETY: `Valid`'s validity is well-defined for all `T: ?Sized`, and is not a
// function of any property of `T` other than its bit validity.
unsafe impl Validity for Valid {
const KIND: ValidityKind = ValidityKind::Valid;
}
/// # Safety
///
/// `DT: CastableFrom<ST, SV, DV>` is sound if `SV = DV = Uninit` or `SV = DV =
/// Initialized`.
pub unsafe trait CastableFrom<ST: ?Sized, SV, DV> {}
// SAFETY: `SV = DV = Uninit`.
unsafe impl<ST: ?Sized, DT: ?Sized> CastableFrom<ST, Uninit, Uninit> for DT {}
// SAFETY: `SV = DV = Initialized`.
unsafe impl<ST: ?Sized, DT: ?Sized> CastableFrom<ST, Initialized, Initialized> for DT {}
/// [`Ptr`](crate::Ptr) referents that permit unsynchronized read operations.
///
/// `T: Read<A, R>` implies that a pointer to `T` with aliasing `A` permits
/// unsynchronized read operations. This can be because `A` is [`Exclusive`] or
/// because `T` does not permit interior mutation.
///
/// # Safety
///
/// `T: Read<A, R>` if either of the following conditions holds:
/// - `A` is [`Exclusive`]
/// - `T` implements [`Immutable`](crate::Immutable)
///
/// As a consequence, if `T: Read<A, R>`, then any `Ptr<T, (A, ...)>` is
/// permitted to perform unsynchronized reads from its referent.
pub trait Read<A: Aliasing, R> {}
impl<A: Aliasing, T: ?Sized + crate::Immutable> Read<A, BecauseImmutable> for T {}
impl<T: ?Sized> Read<Exclusive, BecauseExclusive> for T {}
/// Unsynchronized reads are permitted because only one live [`Ptr`](crate::Ptr)
/// or reference may exist to the referent bytes at a time.
#[derive(Copy, Clone, Debug)]
pub enum BecauseExclusive {}
/// Unsynchronized reads are permitted because no live [`Ptr`](crate::Ptr)s or
/// references permit interior mutation.
#[derive(Copy, Clone, Debug)]
pub enum BecauseImmutable {}
use sealed::Sealed;
mod sealed {
use super::*;
pub trait Sealed {}
impl Sealed for Shared {}
impl Sealed for Exclusive {}
impl Sealed for Unaligned {}
impl Sealed for Aligned {}
impl Sealed for Uninit {}
impl Sealed for AsInitialized {}
impl Sealed for Initialized {}
impl Sealed for Valid {}
impl<A: Sealed, AA: Sealed, V: Sealed> Sealed for (A, AA, V) {}
impl Sealed for BecauseImmutable {}
impl Sealed for BecauseExclusive {}
}
+410
View File
@@ -0,0 +1,410 @@
// SPDX-License-Identifier: BSD-2-Clause OR Apache-2.0 OR MIT
//
// Copyright 2023 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.
//! Abstractions over raw pointers.
#![allow(missing_docs)]
mod inner;
pub mod invariant;
mod ptr;
pub mod transmute;
pub use inner::PtrInner;
pub use invariant::{BecauseExclusive, BecauseImmutable, Read};
pub use ptr::{Ptr, TryWithError};
pub use transmute::*;
use crate::wrappers::ReadOnly;
/// A shorthand for a maybe-valid, maybe-aligned reference. Used as the argument
/// to [`TryFromBytes::is_bit_valid`].
///
/// [`TryFromBytes::is_bit_valid`]: crate::TryFromBytes::is_bit_valid
pub type Maybe<'a, T, Alignment = invariant::Unaligned> =
Ptr<'a, ReadOnly<T>, (invariant::Shared, Alignment, invariant::Initialized)>;
/// Checks if the referent is zeroed.
pub(crate) fn is_zeroed<T, I>(ptr: Ptr<'_, T, I>) -> bool
where
T: crate::Immutable + crate::KnownLayout,
I: invariant::Invariants<Validity = invariant::Initialized>,
I::Aliasing: invariant::Reference,
{
ptr.as_bytes().as_ref().iter().all(
#[inline(always)]
|&byte| byte == 0,
)
}
pub mod cast {
use core::{marker::PhantomData, mem};
use crate::{
layout::{SizeInfo, TrailingSliceLayout},
HasField, KnownLayout, PtrInner,
};
/// A pointer cast or projection.
///
/// # Safety
///
/// The implementation of `project` must satisfy its safety post-condition.
pub unsafe trait Project<Src: ?Sized, Dst: ?Sized> {
/// Projects a pointer from `Src` to `Dst`.
///
/// Users should generally not call `project` directly, and instead
/// should use high-level APIs like [`PtrInner::project`] or
/// [`Ptr::project`].
///
/// [`Ptr::project`]: crate::pointer::Ptr::project
///
/// # Safety
///
/// The returned pointer refers to a non-strict subset of the bytes of
/// `src`'s referent, and has the same provenance as `src`.
fn project(src: PtrInner<'_, Src>) -> *mut Dst;
}
/// A [`Project`] which preserves the address of the referent  a pointer
/// cast.
///
/// # Safety
///
/// A `Cast` projection must preserve the address of the referent. It may
/// shrink the set of referent bytes, and it may change the referent's type.
pub unsafe trait Cast<Src: ?Sized, Dst: ?Sized>: Project<Src, Dst> {}
/// A [`Cast`] which does not shrink the set of referent bytes.
///
/// # Safety
///
/// A `CastExact` projection must preserve the set of referent bytes.
pub unsafe trait CastExact<Src: ?Sized, Dst: ?Sized>: Cast<Src, Dst> {}
/// A no-op pointer cast.
#[derive(Default, Copy, Clone)]
#[allow(missing_debug_implementations)]
pub struct IdCast;
// SAFETY: `project` returns its argument unchanged, and so it is a
// provenance-preserving projection which preserves the set of referent
// bytes.
unsafe impl<T: ?Sized> Project<T, T> for IdCast {
#[inline(always)]
fn project(src: PtrInner<'_, T>) -> *mut T {
src.as_ptr()
}
}
// SAFETY: The `Project::project` impl preserves referent address.
unsafe impl<T: ?Sized> Cast<T, T> for IdCast {}
// SAFETY: The `Project::project` impl preserves referent size.
unsafe impl<T: ?Sized> CastExact<T, T> for IdCast {}
/// A pointer cast which preserves or shrinks the set of referent bytes of
/// a statically-sized referent.
///
/// # Safety
///
/// The implementation of [`Project`] uses a compile-time assertion to
/// guarantee that `Dst` is no larger than `Src`. Thus, `CastSized` has a
/// sound implementation of [`Project`] for all `Src` and `Dst` the caller
/// may pass any `Src` and `Dst` without being responsible for soundness.
#[allow(missing_debug_implementations, missing_copy_implementations)]
pub enum CastSized {}
// SAFETY: By the `static_assert!`, `Dst` is no larger than `Src`,
// and so all casts preserve or shrink the set of referent bytes. All
// operations preserve provenance.
unsafe impl<Src, Dst> Project<Src, Dst> for CastSized {
#[inline(always)]
fn project(src: PtrInner<'_, Src>) -> *mut Dst {
static_assert!(Src, Dst => mem::size_of::<Src>() >= mem::size_of::<Dst>());
src.as_ptr().cast::<Dst>()
}
}
// SAFETY: The `Project::project` impl preserves referent address.
unsafe impl<Src, Dst> Cast<Src, Dst> for CastSized {}
/// A pointer cast which preserves the set of referent bytes of a
/// statically-sized referent.
///
/// # Safety
///
/// The implementation of [`Project`] uses a compile-time assertion to
/// guarantee that `Dst` has the same size as `Src`. Thus, `CastSizedExact`
/// has a sound implementation of [`Project`] for all `Src` and `Dst` the
/// caller may pass any `Src` and `Dst` without being responsible for
/// soundness.
#[allow(missing_debug_implementations, missing_copy_implementations)]
pub enum CastSizedExact {}
// SAFETY: By the `static_assert!`, `Dst` has the same size as `Src`,
// and so all casts preserve the set of referent bytes. All operations
// preserve provenance.
unsafe impl<Src, Dst> Project<Src, Dst> for CastSizedExact {
#[inline(always)]
fn project(src: PtrInner<'_, Src>) -> *mut Dst {
static_assert!(Src, Dst => mem::size_of::<Src>() == mem::size_of::<Dst>());
src.as_ptr().cast::<Dst>()
}
}
// SAFETY: The `Project::project_raw` impl preserves referent address.
unsafe impl<Src, Dst> Cast<Src, Dst> for CastSizedExact {}
// SAFETY: By the `static_assert!`, `Project::project_raw` impl preserves
// referent size.
unsafe impl<Src, Dst> CastExact<Src, Dst> for CastSizedExact {}
/// A pointer cast which preserves or shrinks the set of referent bytes of
/// a dynamically-sized referent.
///
/// # Safety
///
/// The implementation of [`Project`] uses a compile-time assertion to
/// guarantee that the cast preserves the set of referent bytes. Thus,
/// `CastUnsized` has a sound implementation of [`Project`] for all `Src`
/// and `Dst` the caller may pass any `Src` and `Dst` without being
/// responsible for soundness.
#[allow(missing_debug_implementations, missing_copy_implementations)]
pub enum CastUnsized {}
// SAFETY: By the `static_assert!`, `Src` and `Dst` are either:
// - Both sized and equal in size
// - Both slice DSTs with the same trailing slice offset and element size
// and with align_of::<Src>() == align_of::<Dst>(). These ensure that any
// given pointer metadata encodes the same size for both `Src` and `Dst`
// (note that the alignment is required as it affects the amount of
// trailing padding). Thus, `project` preserves the set of referent bytes.
unsafe impl<Src, Dst> Project<Src, Dst> for CastUnsized
where
Src: ?Sized + KnownLayout,
Dst: ?Sized + KnownLayout<PointerMetadata = Src::PointerMetadata>,
{
#[inline(always)]
fn project(src: PtrInner<'_, Src>) -> *mut Dst {
// FIXME: Do we want this to support shrinking casts as well? If so,
// we'll need to remove the `CastExact` impl.
static_assert!(Src: ?Sized + KnownLayout, Dst: ?Sized + KnownLayout => {
let src = <Src as KnownLayout>::LAYOUT;
let dst = <Dst as KnownLayout>::LAYOUT;
match (src.size_info, dst.size_info) {
(SizeInfo::Sized { size: src_size }, SizeInfo::Sized { size: dst_size }) => src_size == dst_size,
(
SizeInfo::SliceDst(TrailingSliceLayout { offset: src_offset, elem_size: src_elem_size }),
SizeInfo::SliceDst(TrailingSliceLayout { offset: dst_offset, elem_size: dst_elem_size })
) => src.align.get() == dst.align.get() && src_offset == dst_offset && src_elem_size == dst_elem_size,
_ => false,
}
});
let metadata = Src::pointer_to_metadata(src.as_ptr());
Dst::raw_from_ptr_len(src.as_non_null().cast::<u8>(), metadata).as_ptr()
}
}
// SAFETY: The `Project::project` impl preserves referent address.
unsafe impl<Src, Dst> Cast<Src, Dst> for CastUnsized
where
Src: ?Sized + KnownLayout,
Dst: ?Sized + KnownLayout<PointerMetadata = Src::PointerMetadata>,
{
}
// SAFETY: By the `static_assert!` in `Project::project`, `Src` and `Dst`
// are either:
// - Both sized and equal in size
// - Both slice DSTs with the same alignment, trailing slice offset, and
// element size. These ensure that any given pointer metadata encodes the
// same size for both `Src` and `Dst` (note that the alignment is required
// as it affects the amount of trailing padding).
unsafe impl<Src, Dst> CastExact<Src, Dst> for CastUnsized
where
Src: ?Sized + KnownLayout,
Dst: ?Sized + KnownLayout<PointerMetadata = Src::PointerMetadata>,
{
}
/// A field projection
///
/// A `Projection` is a [`Project`] which implements projection by
/// delegating to an implementation of [`HasField::project`].
#[allow(missing_debug_implementations, missing_copy_implementations)]
pub struct Projection<F: ?Sized, const VARIANT_ID: i128, const FIELD_ID: i128> {
_never: core::convert::Infallible,
_phantom: PhantomData<F>,
}
// SAFETY: `HasField::project` has the same safety post-conditions as
// `Project::project`.
unsafe impl<T: ?Sized, F, const VARIANT_ID: i128, const FIELD_ID: i128> Project<T, T::Type>
for Projection<F, VARIANT_ID, FIELD_ID>
where
T: HasField<F, VARIANT_ID, FIELD_ID>,
{
#[inline(always)]
fn project(src: PtrInner<'_, T>) -> *mut T::Type {
T::project(src)
}
}
// SAFETY: All `repr(C)` union fields exist at offset 0 within the union [1],
// and so any union projection is actually a cast (ie, preserves address).
//
// [1] Per
// https://doc.rust-lang.org/1.92.0/reference/type-layout.html#reprc-unions,
// it's not *technically* guaranteed that non-maximally-sized fields
// are at offset 0, but it's clear that this is the intention of `repr(C)`
// unions. It says:
//
// > A union declared with `#[repr(C)]` will have the same size and
// > alignment as an equivalent C union declaration in the C language for
// > the target platform.
//
// Note that this only mentions size and alignment, not layout. However,
// C unions *do* guarantee that all fields start at offset 0. [2]
//
// This is also reinforced by
// https://doc.rust-lang.org/1.92.0/reference/items/unions.html#r-items.union.fields.offset:
//
// > Fields might have a non-zero offset (except when the C
// > representation is used); in that case the bits starting at the
// > offset of the fields are read
//
// [2] Per https://port70.net/~nsz/c/c11/n1570.html#6.7.2.1p16:
//
// > The size of a union is sufficient to contain the largest of its
// > members. The value of at most one of the members can be stored in a
// > union object at any time. A pointer to a union object, suitably
// > converted, points to each of its members (or if a member is a
// > bit-field, then to the unit in which it resides), and vice versa.
//
// FIXME(https://github.com/rust-lang/unsafe-code-guidelines/issues/595):
// Cite the documentation once it's updated.
unsafe impl<T: ?Sized, F, const FIELD_ID: i128> Cast<T, T::Type>
for Projection<F, { crate::REPR_C_UNION_VARIANT_ID }, FIELD_ID>
where
T: HasField<F, { crate::REPR_C_UNION_VARIANT_ID }, FIELD_ID>,
{
}
/// A transitive sequence of projections.
///
/// Given `TU: Project` and `UV: Project`, `TransitiveProject<_, TU, UV>` is
/// a [`Project`] which projects by applying `TU` followed by `UV`.
///
/// If `TU: Cast` and `UV: Cast`, then `TransitiveProject<_, TU, UV>: Cast`.
#[allow(missing_debug_implementations)]
pub struct TransitiveProject<U: ?Sized, TU, UV> {
_never: core::convert::Infallible,
_projections: PhantomData<(TU, UV)>,
// On our MSRV (1.56), the debuginfo for a tuple containing both an
// uninhabited type and a DST causes an ICE. We split `U` from `TU` and
// `UV` to avoid this situation.
_u: PhantomData<U>,
}
// SAFETY: Since `TU::project` and `UV::project` are each
// provenance-preserving operations which preserve or shrink the set of
// referent bytes, so is their composition.
unsafe impl<T, U, V, TU, UV> Project<T, V> for TransitiveProject<U, TU, UV>
where
T: ?Sized,
U: ?Sized,
V: ?Sized,
TU: Project<T, U>,
UV: Project<U, V>,
{
#[inline(always)]
fn project(t: PtrInner<'_, T>) -> *mut V {
t.project::<_, TU>().project::<_, UV>().as_ptr()
}
}
// SAFETY: Since the `Project::project` impl delegates to `TU::project` and
// `UV::project`, and since `TU` and `UV` are `Cast`, the `Project::project`
// impl preserves the address of the referent.
unsafe impl<T, U, V, TU, UV> Cast<T, V> for TransitiveProject<U, TU, UV>
where
T: ?Sized,
U: ?Sized,
V: ?Sized,
TU: Cast<T, U>,
UV: Cast<U, V>,
{
}
// SAFETY: Since the `Project::project` impl delegates to `TU::project` and
// `UV::project`, and since `TU` and `UV` are `CastExact`, the `Project::project`
// impl preserves the set of referent bytes.
unsafe impl<T, U, V, TU, UV> CastExact<T, V> for TransitiveProject<U, TU, UV>
where
T: ?Sized,
U: ?Sized,
V: ?Sized,
TU: CastExact<T, U>,
UV: CastExact<U, V>,
{
}
/// A cast from `T` to `[u8]`.
#[allow(missing_copy_implementations, missing_debug_implementations)]
pub struct AsBytesCast;
// SAFETY: `project` constructs a pointer with the same address as `src`
// and with a referent of the same size as `*src`. It does this using
// provenance-preserving operations.
//
// FIXME(https://github.com/rust-lang/unsafe-code-guidelines/issues/594):
// Technically, this proof assumes that `*src` is contiguous (the same is
// true of other proofs in this codebase). Is this guaranteed anywhere?
unsafe impl<T: ?Sized + KnownLayout> Project<T, [u8]> for AsBytesCast {
#[inline(always)]
fn project(src: PtrInner<'_, T>) -> *mut [u8] {
let bytes = match T::size_of_val_raw(src.as_non_null()) {
Some(bytes) => bytes,
// SAFETY: `KnownLayout::size_of_val_raw` promises to always
// return `Some` so long as the resulting size fits in a
// `usize`. By invariant on `PtrInner`, `src` refers to a range
// of bytes whose size fits in an `isize`, which implies that it
// also fits in a `usize`.
None => unsafe { core::hint::unreachable_unchecked() },
};
core::ptr::slice_from_raw_parts_mut(src.as_ptr().cast::<u8>(), bytes)
}
}
// SAFETY: The `Project::project` impl preserves referent address.
unsafe impl<T: ?Sized + KnownLayout> Cast<T, [u8]> for AsBytesCast {}
// SAFETY: The `Project::project` impl preserves the set of referent bytes.
unsafe impl<T: ?Sized + KnownLayout> CastExact<T, [u8]> for AsBytesCast {}
/// A cast from any type to `()`.
#[allow(missing_copy_implementations, missing_debug_implementations)]
pub struct CastToUnit;
// SAFETY: The `project` implementation projects to a subset of its
// argument's referent using provenance-preserving operations.
unsafe impl<T: ?Sized> Project<T, ()> for CastToUnit {
#[inline(always)]
fn project(src: PtrInner<'_, T>) -> *mut () {
src.as_ptr().cast::<()>()
}
}
// SAFETY: The `project` implementation preserves referent address.
unsafe impl<T: ?Sized> Cast<T, ()> for CastToUnit {}
}
File diff suppressed because it is too large Load Diff
+522
View File
@@ -0,0 +1,522 @@
// SPDX-License-Identifier: BSD-2-Clause OR Apache-2.0 OR MIT
//
// Copyright 2025 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.
#![allow(missing_docs)]
use core::{
cell::{Cell, UnsafeCell},
mem::{ManuallyDrop, MaybeUninit},
num::Wrapping,
};
use crate::{
pointer::{
cast::{self, CastExact, CastSizedExact},
invariant::*,
},
FromBytes, Immutable, IntoBytes, Unalign,
};
/// Transmutations which are sound to attempt, conditional on validating the bit
/// validity of the destination type.
///
/// If a `Ptr` transmutation is `TryTransmuteFromPtr`, then it is sound to
/// perform that transmutation so long as some additional mechanism is used to
/// validate that the referent is bit-valid for the destination type. That
/// validation mechanism could be a type bound (such as `TransmuteFrom`) or a
/// runtime validity check.
///
/// # Safety
///
/// ## Post-conditions
///
/// Given `Dst: TryTransmuteFromPtr<Src, A, SV, DV, C, _>`, callers may assume
/// the following:
///
/// Given `src: Ptr<'a, Src, (A, _, SV)>`, if the referent of `src` is
/// `DV`-valid for `Dst`, then it is sound to transmute `src` into `dst: Ptr<'a,
/// Dst, (A, Unaligned, DV)>` using `C`.
///
/// ## Pre-conditions
///
/// Given `src: Ptr<Src, (A, _, SV)>` and `dst: Ptr<Dst, (A, Unaligned, DV)>`,
/// `Dst: TryTransmuteFromPtr<Src, A, SV, DV, C, _>` is sound if all of the
/// following hold:
/// - Forwards transmutation: Either of the following hold:
/// - So long as `dst` is active, no mutation of `dst`'s referent is allowed
/// except via `dst` itself
/// - The set of `DV`-valid referents of `dst` is a superset of the set of
/// `SV`-valid referents of `src` (NOTE: this condition effectively bans
/// shrinking or overwriting transmutes, which cannot satisfy this
/// condition)
/// - Reverse transmutation: Either of the following hold:
/// - `dst` does not permit mutation of its referent
/// - The set of `DV`-valid referents of `dst` is a subset of the set of
/// `SV`-valid referents of `src` (NOTE: this condition effectively bans
/// shrinking or overwriting transmutes, which cannot satisfy this
/// condition)
/// - No safe code, given access to `src` and `dst`, can cause undefined
/// behavior: Any of the following hold:
/// - `A` is `Exclusive`
/// - `Src: Immutable` and `Dst: Immutable`
/// - It is sound for shared code to operate on a `&Src` and `&Dst` which
/// reference the same byte range at the same time
///
/// ## Proof
///
/// Given:
/// - `src: Ptr<'a, Src, (A, _, SV)>`
/// - `src`'s referent is `DV`-valid for `Dst`
///
/// We are trying to prove that it is sound to perform a cast from `src` to a
/// `dst: Ptr<'a, Dst, (A, Unaligned, DV)>` using `C`. We need to prove that
/// such a cast does not violate any of `src`'s invariants, and that it
/// satisfies all invariants of the destination `Ptr` type.
///
/// First, by `C: CastExact`, `src`'s address is unchanged, so it still satisfies
/// its alignment. Since `dst`'s alignment is `Unaligned`, it trivially satisfies
/// its alignment.
///
/// Second, aliasing is either `Exclusive` or `Shared`:
/// - If it is `Exclusive`, then both `src` and `dst` satisfy `Exclusive`
/// aliasing trivially: since `src` and `dst` have the same lifetime, `src` is
/// inaccessible so long as `dst` is alive, and no other live `Ptr`s or
/// references may reference the same referent.
/// - If it is `Shared`, then either:
/// - `Src: Immutable` and `Dst: Immutable`, and so neither `src` nor `dst`
/// permit interior mutation.
/// - It is explicitly sound for safe code to operate on a `&Src` and a `&Dst`
/// pointing to the same byte range at the same time.
///
/// Third, `src`'s validity is satisfied. By invariant, `src`'s referent began
/// as an `SV`-valid `Src`. It is guaranteed to remain so, as either of the
/// following hold:
/// - `dst` does not permit mutation of its referent.
/// - The set of `DV`-valid referents of `dst` is a subset of the set of
/// `SV`-valid referents of `src`. Thus, any value written via `dst` is
/// guaranteed to be an `SV`-valid referent of `src`.
///
/// Fourth, `dst`'s validity is satisfied. It is a given of this proof that the
/// referent is `DV`-valid for `Dst`. It is guaranteed to remain so, as either
/// of the following hold:
/// - So long as `dst` is active, no mutation of the referent is allowed except
/// via `dst` itself.
/// - The set of `DV`-valid referents of `dst` is a superset of the set of
/// `SV`-valid referents of `src`. Thus, any value written via `src` is
/// guaranteed to be a `DV`-valid referent of `dst`.
pub unsafe trait TryTransmuteFromPtr<
Src: ?Sized,
A: Aliasing,
SV: Validity,
DV: Validity,
C: CastExact<Src, Self>,
R,
>
{
}
#[allow(missing_copy_implementations, missing_debug_implementations)]
pub enum BecauseMutationCompatible {}
// SAFETY:
// - Forwards transmutation: By `Dst: MutationCompatible<Src, A, SV, DV, _>`, we
// know that at least one of the following holds:
// - So long as `dst: Ptr<Dst>` is active, no mutation of its referent is
// allowed except via `dst` itself if either of the following hold:
// - Aliasing is `Exclusive`, in which case, so long as the `Dst` `Ptr`
// exists, no mutation is permitted except via that `Ptr`
// - Aliasing is `Shared`, `Src: Immutable`, and `Dst: Immutable`, in which
// case no mutation is possible via either `Ptr`
// - Since the underlying cast is size-preserving, `dst` addresses the same
// referent as `src`. By `Dst: TransmuteFrom<Src, SV, DV>`, the set of
// `DV`-valid referents of `dst` is a superset of the set of `SV`-valid
// referents of `src`.
// - Reverse transmutation: Since the underlying cast is size-preserving, `dst`
// addresses the same referent as `src`. By `Src: TransmuteFrom<Dst, DV, SV>`,
// the set of `DV`-valid referents of `src` is a subset of the set of
// `SV`-valid referents of `dst`.
// - No safe code, given access to `src` and `dst`, can cause undefined
// behavior: By `Dst: MutationCompatible<Src, A, SV, DV, _>`, at least one of
// the following holds:
// - `A` is `Exclusive`
// - `Src: Immutable` and `Dst: Immutable`
// - `Dst: InvariantsEq<Src>`, which guarantees that `Src` and `Dst` have the
// same invariants, and permit interior mutation on the same byte ranges
unsafe impl<Src, Dst, SV, DV, A, C, R>
TryTransmuteFromPtr<Src, A, SV, DV, C, (BecauseMutationCompatible, R)> for Dst
where
A: Aliasing,
SV: Validity,
DV: Validity,
Src: TransmuteFrom<Dst, DV, SV> + ?Sized,
Dst: MutationCompatible<Src, A, SV, DV, R> + ?Sized,
C: CastExact<Src, Dst>,
{
}
// SAFETY:
// - Forwards transmutation: Since aliasing is `Shared` and `Src: Immutable`,
// `src` does not permit mutation of its referent.
// - Reverse transmutation: Since aliasing is `Shared` and `Dst: Immutable`,
// `dst` does not permit mutation of its referent.
// - No safe code, given access to `src` and `dst`, can cause undefined
// behavior: `Src: Immutable` and `Dst: Immutable`
unsafe impl<Src, Dst, SV, DV, C> TryTransmuteFromPtr<Src, Shared, SV, DV, C, BecauseImmutable>
for Dst
where
SV: Validity,
DV: Validity,
Src: Immutable + ?Sized,
Dst: Immutable + ?Sized,
C: CastExact<Src, Dst>,
{
}
/// Denotes that `src: Ptr<Src, (A, _, SV)>` and `dst: Ptr<Self, (A, _, DV)>`,
/// referencing the same referent at the same time, cannot be used by safe code
/// to break library safety invariants of `Src` or `Self`.
///
/// # Safety
///
/// At least one of the following must hold:
/// - `Src: Read<A, _>` and `Self: Read<A, _>`
/// - `Self: InvariantsEq<Src>`, and, for some `V`:
/// - `Dst: TransmuteFrom<Src, V, V>`
/// - `Src: TransmuteFrom<Dst, V, V>`
pub unsafe trait MutationCompatible<Src: ?Sized, A: Aliasing, SV, DV, R> {}
#[allow(missing_copy_implementations, missing_debug_implementations)]
pub enum BecauseRead {}
// SAFETY: `Src: Read<A, _>` and `Dst: Read<A, _>`.
unsafe impl<Src: ?Sized, Dst: ?Sized, A: Aliasing, SV: Validity, DV: Validity, R>
MutationCompatible<Src, A, SV, DV, (BecauseRead, R)> for Dst
where
Src: Read<A, R>,
Dst: Read<A, R>,
{
}
/// Denotes that two types have the same invariants.
///
/// # Safety
///
/// It is sound for safe code to operate on a `&T` and a `&Self` pointing to the
/// same referent at the same time - no such safe code can cause undefined
/// behavior.
pub unsafe trait InvariantsEq<T: ?Sized> {}
// SAFETY: Trivially sound to have multiple `&T` pointing to the same referent.
unsafe impl<T: ?Sized> InvariantsEq<T> for T {}
// SAFETY: `Dst: InvariantsEq<Src> + TransmuteFrom<Src, SV, DV>`, and `Src:
// TransmuteFrom<Dst, DV, SV>`.
unsafe impl<Src: ?Sized, Dst: ?Sized, A: Aliasing, SV: Validity, DV: Validity>
MutationCompatible<Src, A, SV, DV, BecauseInvariantsEq> for Dst
where
Src: TransmuteFrom<Dst, DV, SV>,
Dst: TransmuteFrom<Src, SV, DV> + InvariantsEq<Src>,
{
}
#[allow(missing_debug_implementations, missing_copy_implementations)]
pub enum BecauseInvariantsEq {}
macro_rules! unsafe_impl_invariants_eq {
($tyvar:ident => $t:ty, $u:ty) => {{
crate::util::macros::__unsafe();
// SAFETY: The caller promises that this is sound.
unsafe impl<$tyvar> InvariantsEq<$t> for $u {}
// SAFETY: The caller promises that this is sound.
unsafe impl<$tyvar> InvariantsEq<$u> for $t {}
}};
}
impl_transitive_transmute_from!(T => MaybeUninit<T> => T => Wrapping<T>);
impl_transitive_transmute_from!(T => Wrapping<T> => T => MaybeUninit<T>);
// SAFETY: `ManuallyDrop<T>` has the same size and bit validity as `T` [1], and
// implements `Deref<Target = T>` [2]. Thus, it is already possible for safe
// code to obtain a `&T` and a `&ManuallyDrop<T>` to the same referent at the
// same time.
//
// [1] Per https://doc.rust-lang.org/1.81.0/std/mem/struct.ManuallyDrop.html:
//
// `ManuallyDrop<T>` is guaranteed to have the same layout and bit
// validity as `T`
//
// [2] https://doc.rust-lang.org/1.81.0/std/mem/struct.ManuallyDrop.html#impl-Deref-for-ManuallyDrop%3CT%3E
unsafe impl<T: ?Sized> InvariantsEq<T> for ManuallyDrop<T> {}
// SAFETY: See previous safety comment.
unsafe impl<T: ?Sized> InvariantsEq<ManuallyDrop<T>> for T {}
/// Transmutations which are always sound.
///
/// `TransmuteFromPtr` is a shorthand for [`TryTransmuteFromPtr`] and
/// [`TransmuteFrom`].
///
/// # Safety
///
/// `Dst: TransmuteFromPtr<Src, A, SV, DV, _>` is equivalent to `Dst:
/// TryTransmuteFromPtr<Src, A, SV, DV, _> + TransmuteFrom<Src, SV, DV>`.
pub unsafe trait TransmuteFromPtr<
Src: ?Sized,
A: Aliasing,
SV: Validity,
DV: Validity,
C: CastExact<Src, Self>,
R,
>: TryTransmuteFromPtr<Src, A, SV, DV, C, R> + TransmuteFrom<Src, SV, DV>
{
}
// SAFETY: The `where` bounds are equivalent to the safety invariant on
// `TransmuteFromPtr`.
unsafe impl<
Src: ?Sized,
Dst: ?Sized,
A: Aliasing,
SV: Validity,
DV: Validity,
C: CastExact<Src, Dst>,
R,
> TransmuteFromPtr<Src, A, SV, DV, C, R> for Dst
where
Dst: TransmuteFrom<Src, SV, DV> + TryTransmuteFromPtr<Src, A, SV, DV, C, R>,
{
}
/// Denotes that any `SV`-valid `Src` may soundly be transmuted into a
/// `DV`-valid `Self`.
///
/// # Safety
///
/// Given `src: Ptr<Src, (_, _, SV)>` and `dst: Ptr<Dst, (_, _, DV)>`, if the
/// referents of `src` and `dst` are the same size, then the set of bit patterns
/// allowed to appear in `src`'s referent must be a subset of the set allowed to
/// appear in `dst`'s referent.
///
/// If the referents are not the same size, then `Dst: TransmuteFrom<Src, SV,
/// DV>` conveys no safety guarantee.
pub unsafe trait TransmuteFrom<Src: ?Sized, SV, DV> {}
/// Carries the ability to perform a size-preserving cast or conversion from a
/// raw pointer to `Src` to a raw pointer to `Self`.
///
/// The cast/conversion is carried by the associated [`CastFrom`] type, and
/// may be a no-op cast (without updating pointer metadata) or a conversion
/// which updates pointer metadata.
///
/// # Safety
///
/// `SizeEq` on its own conveys no safety guarantee. Any safety guarantees come
/// from the safety invariants on the associated [`CastFrom`] type, specifically
/// the [`CastExact`] bound.
///
/// [`CastFrom`]: SizeEq::CastFrom
/// [`CastExact`]: CastExact
pub trait SizeEq<Src: ?Sized> {
type CastFrom: CastExact<Src, Self>;
}
impl<T: ?Sized> SizeEq<T> for T {
type CastFrom = cast::IdCast;
}
// SAFETY: Since `Src: IntoBytes`, the set of valid `Src`'s is the set of
// initialized bit patterns, which is exactly the set allowed in the referent of
// any `Initialized` `Ptr`.
unsafe impl<Src, Dst> TransmuteFrom<Src, Valid, Initialized> for Dst
where
Src: IntoBytes + ?Sized,
Dst: ?Sized,
{
}
// SAFETY: Since `Dst: FromBytes`, any initialized bit pattern may appear in the
// referent of a `Ptr<Dst, (_, _, Valid)>`. This is exactly equal to the set of
// bit patterns which may appear in the referent of any `Initialized` `Ptr`.
unsafe impl<Src, Dst> TransmuteFrom<Src, Initialized, Valid> for Dst
where
Src: ?Sized,
Dst: FromBytes + ?Sized,
{
}
// FIXME(#2354): This seems like a smell - the soundness of this bound has
// nothing to do with `Src` or `Dst` - we're basically just saying `[u8; N]` is
// transmutable into `[u8; N]`.
// SAFETY: The set of allowed bit patterns in the referent of any `Initialized`
// `Ptr` is the same regardless of referent type.
unsafe impl<Src, Dst> TransmuteFrom<Src, Initialized, Initialized> for Dst
where
Src: ?Sized,
Dst: ?Sized,
{
}
// FIXME(#2354): This seems like a smell - the soundness of this bound has
// nothing to do with `Dst` - we're basically just saying that any type is
// transmutable into `MaybeUninit<[u8; N]>`.
// SAFETY: A `Dst` with validity `Uninit` permits any byte sequence, and
// therefore can be transmuted from any value.
unsafe impl<Src, Dst, V> TransmuteFrom<Src, V, Uninit> for Dst
where
Src: ?Sized,
Dst: ?Sized,
V: Validity,
{
}
// SAFETY:
// - `ManuallyDrop<T>` has the same size as `T` [1]
// - `ManuallyDrop<T>` has the same validity as `T` [1]
//
// [1] Per https://doc.rust-lang.org/1.81.0/std/mem/struct.ManuallyDrop.html:
//
// `ManuallyDrop<T>` is guaranteed to have the same layout and bit validity as
// `T`
#[allow(clippy::multiple_unsafe_ops_per_block)]
const _: () = unsafe { unsafe_impl_for_transparent_wrapper!(pub T: ?Sized => ManuallyDrop<T>) };
// SAFETY:
// - `Unalign<T>` promises to have the same size as `T`.
// - `Unalign<T>` promises to have the same validity as `T`.
#[allow(clippy::multiple_unsafe_ops_per_block)]
const _: () = unsafe { unsafe_impl_for_transparent_wrapper!(pub T => Unalign<T>) };
// SAFETY: `Unalign<T>` promises to have the same size and validity as `T`.
// Given `u: &Unalign<T>`, it is already possible to obtain `let t =
// u.try_deref().unwrap()`. Because `Unalign<T>` has the same size as `T`, the
// returned `&T` must point to the same referent as `u`, and thus it must be
// sound for these two references to exist at the same time since it's already
// possible for safe code to get into this state.
#[allow(clippy::multiple_unsafe_ops_per_block)]
const _: () = unsafe { unsafe_impl_invariants_eq!(T => T, Unalign<T>) };
// SAFETY:
// - `Wrapping<T>` has the same size as `T` [1].
// - `Wrapping<T>` has only one field, which is `pub` [2]. We are also
// guaranteed per that `Wrapping<T>` has the same layout as `T` [1]. The only
// way for both of these to be true simultaneously is for `Wrapping<T>` to
// have the same bit validity as `T`. In particular, in order to change the
// bit validity, one of the following would need to happen:
// - `Wrapping` could change its `repr`, but this would violate the layout
// guarantee.
// - `Wrapping` could add or change its fields, but this would be a
// stability-breaking change.
//
// [1] Per https://doc.rust-lang.org/1.85.0/core/num/struct.Wrapping.html#layout-1:
//
// `Wrapping<T>` is guaranteed to have the same layout and ABI as `T`.
//
// [2] Definition from https://doc.rust-lang.org/1.85.0/core/num/struct.Wrapping.html:
//
// ```
// #[repr(transparent)]
// pub struct Wrapping<T>(pub T);
// ```
#[allow(clippy::multiple_unsafe_ops_per_block)]
const _: () = unsafe { unsafe_impl_for_transparent_wrapper!(pub T => Wrapping<T>) };
// SAFETY: By the preceding safety proof, `Wrapping<T>` and `T` have the same
// layout and bit validity. Since a `Wrapping<T>`'s `T` field is `pub`, given
// `w: &Wrapping<T>`, it's possible to do `let t = &w.t`, which means that it's
// already possible for safe code to obtain a `&Wrapping<T>` and a `&T` pointing
// to the same referent at the same time. Thus, this must be sound.
#[allow(clippy::multiple_unsafe_ops_per_block)]
const _: () = unsafe { unsafe_impl_invariants_eq!(T => T, Wrapping<T>) };
// SAFETY:
// - `UnsafeCell<T>` has the same size as `T` [1].
// - Per [1], `UnsafeCell<T>` has the same bit validity as `T`. Technically the
// term "representation" doesn't guarantee this, but the subsequent sentence
// in the documentation makes it clear that this is the intention.
//
// [1] Per https://doc.rust-lang.org/1.81.0/core/cell/struct.UnsafeCell.html#memory-layout:
//
// `UnsafeCell<T>` has the same in-memory representation as its inner type
// `T`. A consequence of this guarantee is that it is possible to convert
// between `T` and `UnsafeCell<T>`.
#[allow(clippy::multiple_unsafe_ops_per_block)]
const _: () = unsafe { unsafe_impl_for_transparent_wrapper!(pub T: ?Sized => UnsafeCell<T>) };
// SAFETY:
// - `Cell<T>` has the same size as `T` [1].
// - Per [1], `Cell<T>` has the same bit validity as `T`. Technically the term
// "representation" doesn't guarantee this, but it does promise to have the
// "same memory layout and caveats as `UnsafeCell<T>`." The `UnsafeCell` docs
// [2] make it clear that bit validity is the intention even if that phrase
// isn't used.
//
// [1] Per https://doc.rust-lang.org/1.85.0/std/cell/struct.Cell.html#memory-layout:
//
// `Cell<T>` has the same memory layout and caveats as `UnsafeCell<T>`. In
// particular, this means that `Cell<T>` has the same in-memory representation
// as its inner type `T`.
//
// [2] Per https://doc.rust-lang.org/1.81.0/core/cell/struct.UnsafeCell.html#memory-layout:
//
// `UnsafeCell<T>` has the same in-memory representation as its inner type
// `T`. A consequence of this guarantee is that it is possible to convert
// between `T` and `UnsafeCell<T>`.
#[allow(clippy::multiple_unsafe_ops_per_block)]
const _: () = unsafe { unsafe_impl_for_transparent_wrapper!(pub T: ?Sized => Cell<T>) };
impl_transitive_transmute_from!(T: ?Sized => Cell<T> => T => UnsafeCell<T>);
impl_transitive_transmute_from!(T: ?Sized => UnsafeCell<T> => T => Cell<T>);
// SAFETY: `MaybeUninit<T>` has no validity requirements. Currently this is not
// explicitly guaranteed, but it's obvious from `MaybeUninit`'s documentation
// that this is the intention:
// https://doc.rust-lang.org/1.85.0/core/mem/union.MaybeUninit.html
unsafe impl<T> TransmuteFrom<T, Uninit, Valid> for MaybeUninit<T> {}
impl<T> SizeEq<T> for MaybeUninit<T> {
type CastFrom = CastSizedExact;
}
impl<T> SizeEq<MaybeUninit<T>> for T {
type CastFrom = CastSizedExact;
}
#[cfg(test)]
mod tests {
use super::*;
use crate::pointer::cast::Project as _;
fn test_size_eq<Src, Dst: SizeEq<Src>>(mut src: Src) {
let _: *mut Dst =
<Dst as SizeEq<Src>>::CastFrom::project(crate::pointer::PtrInner::from_mut(&mut src));
}
#[test]
fn test_transmute_coverage() {
// SizeEq<T> for MaybeUninit<T>
test_size_eq::<u8, MaybeUninit<u8>>(0u8);
// SizeEq<MaybeUninit<T>> for T
test_size_eq::<MaybeUninit<u8>, u8>(MaybeUninit::<u8>::new(0));
// Transitive: MaybeUninit<T> -> Wrapping<T>
// T => MaybeUninit<T> => T => Wrapping<T>
test_size_eq::<u8, Wrapping<u8>>(0u8);
// T => Wrapping<T> => T => MaybeUninit<T>
test_size_eq::<Wrapping<u8>, MaybeUninit<u8>>(Wrapping(0u8));
// T: ?Sized => Cell<T> => T => UnsafeCell<T>
test_size_eq::<Cell<u8>, UnsafeCell<u8>>(Cell::new(0u8));
// T: ?Sized => UnsafeCell<T> => T => Cell<T>
test_size_eq::<UnsafeCell<u8>, Cell<u8>>(UnsafeCell::new(0u8));
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+944
View File
@@ -0,0 +1,944 @@
// SPDX-License-Identifier: BSD-2-Clause OR Apache-2.0 OR MIT
//
// Copyright 2023 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.
#[macro_use]
pub(crate) mod macros;
#[doc(hidden)]
pub mod macro_util;
use core::{
marker::PhantomData,
mem::{self, ManuallyDrop},
num::NonZeroUsize,
ptr::NonNull,
};
use super::*;
use crate::pointer::{
invariant::{Exclusive, Shared, Valid},
SizeEq, TransmuteFromPtr,
};
/// Like [`PhantomData`], but [`Send`] and [`Sync`] regardless of whether the
/// wrapped `T` is.
pub(crate) struct SendSyncPhantomData<T: ?Sized>(PhantomData<T>);
// SAFETY: `SendSyncPhantomData` does not enable any behavior which isn't sound
// to be called from multiple threads.
unsafe impl<T: ?Sized> Send for SendSyncPhantomData<T> {}
// SAFETY: `SendSyncPhantomData` does not enable any behavior which isn't sound
// to be called from multiple threads.
unsafe impl<T: ?Sized> Sync for SendSyncPhantomData<T> {}
impl<T: ?Sized> Default for SendSyncPhantomData<T> {
fn default() -> SendSyncPhantomData<T> {
SendSyncPhantomData(PhantomData)
}
}
impl<T: ?Sized> PartialEq for SendSyncPhantomData<T> {
fn eq(&self, _other: &Self) -> bool {
true
}
}
impl<T: ?Sized> Eq for SendSyncPhantomData<T> {}
impl<T: ?Sized> Clone for SendSyncPhantomData<T> {
fn clone(&self) -> Self {
SendSyncPhantomData(PhantomData)
}
}
#[cfg(miri)]
extern "Rust" {
/// Miri-provided intrinsic that marks the pointer `ptr` as aligned to
/// `align`.
///
/// This intrinsic is used to inform Miri's symbolic alignment checker that
/// a pointer is aligned, even if Miri cannot statically deduce that fact.
/// This is often required when performing raw pointer arithmetic or casts
/// where the alignment is guaranteed by runtime checks or invariants that
/// Miri is not aware of.
pub(crate) fn miri_promise_symbolic_alignment(ptr: *const (), align: usize);
}
pub(crate) trait AsAddress {
fn addr(self) -> usize;
}
impl<T: ?Sized> AsAddress for &T {
#[inline(always)]
fn addr(self) -> usize {
let ptr: *const T = self;
AsAddress::addr(ptr)
}
}
impl<T: ?Sized> AsAddress for &mut T {
#[inline(always)]
fn addr(self) -> usize {
let ptr: *const T = self;
AsAddress::addr(ptr)
}
}
impl<T: ?Sized> AsAddress for NonNull<T> {
#[inline(always)]
fn addr(self) -> usize {
AsAddress::addr(self.as_ptr())
}
}
impl<T: ?Sized> AsAddress for *const T {
#[inline(always)]
fn addr(self) -> usize {
// FIXME(#181), FIXME(https://github.com/rust-lang/rust/issues/95228):
// Use `.addr()` instead of `as usize` once it's stable, and get rid of
// this `allow`. Currently, `as usize` is the only way to accomplish
// this.
#[allow(clippy::as_conversions)]
#[cfg_attr(
__ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS,
allow(lossy_provenance_casts)
)]
return self.cast::<()>() as usize;
}
}
impl<T: ?Sized> AsAddress for *mut T {
#[inline(always)]
fn addr(self) -> usize {
let ptr: *const T = self;
AsAddress::addr(ptr)
}
}
/// Validates that `t` is aligned to `align_of::<U>()`.
#[inline(always)]
pub(crate) fn validate_aligned_to<T: AsAddress, U>(t: T) -> Result<(), AlignmentError<(), U>> {
// `mem::align_of::<U>()` is guaranteed to return a non-zero value, which in
// turn guarantees that this mod operation will not panic.
#[allow(clippy::arithmetic_side_effects)]
let remainder = t.addr() % mem::align_of::<U>();
if remainder == 0 {
Ok(())
} else {
// SAFETY: We just confirmed that `t.addr() % align_of::<U>() != 0`.
// That's only possible if `align_of::<U>() > 1`.
Err(unsafe { AlignmentError::new_unchecked(()) })
}
}
/// Returns the bytes needed to pad `len` to the next multiple of `align`.
///
/// This function assumes that align is a power of two; there are no guarantees
/// on the answer it gives if this is not the case.
#[cfg_attr(
kani,
kani::requires(len <= DstLayout::MAX_SIZE),
kani::requires(align.is_power_of_two()),
kani::ensures(|&p| (len + p) % align.get() == 0),
// Ensures that we add the minimum required padding.
kani::ensures(|&p| p < align.get()),
)]
#[cfg_attr(not(zerocopy_inline_always), inline)]
#[cfg_attr(zerocopy_inline_always, inline(always))]
pub(crate) const fn padding_needed_for(len: usize, align: NonZeroUsize) -> usize {
#[cfg(kani)]
#[kani::proof_for_contract(padding_needed_for)]
fn proof() {
padding_needed_for(kani::any(), kani::any());
}
// Abstractly, we want to compute:
// align - (len % align).
// Handling the case where len%align is 0.
// Because align is a power of two, len % align = len & (align-1).
// Guaranteed not to underflow as align is nonzero.
#[allow(clippy::arithmetic_side_effects)]
let mask = align.get() - 1;
// To efficiently subtract this value from align, we can use the bitwise
// complement.
// Note that ((!len) & (align-1)) gives us a number that with (len &
// (align-1)) sums to align-1. So subtracting 1 from x before taking the
// complement subtracts `len` from `align`. Some quick inspection of
// cases shows that this also handles the case where `len % align = 0`
// correctly too: len-1 % align then equals align-1, so the complement mod
// align will be 0, as desired.
//
// The following reasoning can be verified quickly by an SMT solver
// supporting the theory of bitvectors:
// ```smtlib
// ; Naive implementation of padding
// (define-fun padding1 (
// (len (_ BitVec 32))
// (align (_ BitVec 32))) (_ BitVec 32)
// (ite
// (= (_ bv0 32) (bvand len (bvsub align (_ bv1 32))))
// (_ bv0 32)
// (bvsub align (bvand len (bvsub align (_ bv1 32))))))
//
// ; The implementation below
// (define-fun padding2 (
// (len (_ BitVec 32))
// (align (_ BitVec 32))) (_ BitVec 32)
// (bvand (bvnot (bvsub len (_ bv1 32))) (bvsub align (_ bv1 32))))
//
// (define-fun is-power-of-two ((x (_ BitVec 32))) Bool
// (= (_ bv0 32) (bvand x (bvsub x (_ bv1 32)))))
//
// (declare-const len (_ BitVec 32))
// (declare-const align (_ BitVec 32))
// ; Search for a case where align is a power of two and padding2 disagrees
// ; with padding1
// (assert (and (is-power-of-two align)
// (not (= (padding1 len align) (padding2 len align)))))
// (simplify (padding1 (_ bv300 32) (_ bv32 32))) ; 20
// (simplify (padding2 (_ bv300 32) (_ bv32 32))) ; 20
// (simplify (padding1 (_ bv322 32) (_ bv32 32))) ; 30
// (simplify (padding2 (_ bv322 32) (_ bv32 32))) ; 30
// (simplify (padding1 (_ bv8 32) (_ bv8 32))) ; 0
// (simplify (padding2 (_ bv8 32) (_ bv8 32))) ; 0
// (check-sat) ; unsat, also works for 64-bit bitvectors
// ```
!(len.wrapping_sub(1)) & mask
}
/// Rounds `n` down to the largest value `m` such that `m <= n` and `m % align
/// == 0`.
///
/// # Panics
///
/// May panic if `align` is not a power of two. Even if it doesn't panic in this
/// case, it will produce nonsense results.
#[inline(always)]
#[cfg_attr(
kani,
kani::requires(align.is_power_of_two()),
kani::ensures(|&m| m <= n && m % align.get() == 0),
// Guarantees that `m` is the *largest* value such that `m % align == 0`.
kani::ensures(|&m| {
// If this `checked_add` fails, then the next multiple would wrap
// around, which trivially satisfies the "largest value" requirement.
m.checked_add(align.get()).map(|next_mul| next_mul > n).unwrap_or(true)
})
)]
pub(crate) const fn round_down_to_next_multiple_of_alignment(
n: usize,
align: NonZeroUsize,
) -> usize {
#[cfg(kani)]
#[kani::proof_for_contract(round_down_to_next_multiple_of_alignment)]
fn proof() {
round_down_to_next_multiple_of_alignment(kani::any(), kani::any());
}
let align = align.get();
#[cfg(not(no_zerocopy_panic_in_const_and_vec_try_reserve_1_57_0))]
debug_assert!(align.is_power_of_two());
// Subtraction can't underflow because `align.get() >= 1`.
#[allow(clippy::arithmetic_side_effects)]
let mask = !(align - 1);
n & mask
}
#[cfg_attr(not(zerocopy_inline_always), inline)]
#[cfg_attr(zerocopy_inline_always, inline(always))]
pub(crate) const fn max(a: NonZeroUsize, b: NonZeroUsize) -> NonZeroUsize {
if a.get() < b.get() {
b
} else {
a
}
}
#[cfg_attr(not(zerocopy_inline_always), inline)]
#[cfg_attr(zerocopy_inline_always, inline(always))]
pub(crate) const fn min(a: NonZeroUsize, b: NonZeroUsize) -> NonZeroUsize {
if a.get() > b.get() {
b
} else {
a
}
}
/// Copies `src` into the prefix of `dst`.
///
/// # Safety
///
/// The caller guarantees that `src.len() <= dst.len()`.
#[inline(always)]
pub(crate) unsafe fn copy_unchecked(src: &[u8], dst: &mut [u8]) {
debug_assert!(src.len() <= dst.len());
// SAFETY: This invocation satisfies the safety contract of
// copy_nonoverlapping [1]:
// - `src.as_ptr()` is trivially valid for reads of `src.len()` bytes
// - `dst.as_ptr()` is valid for writes of `src.len()` bytes, because the
// caller has promised that `src.len() <= dst.len()`
// - `src` and `dst` are, trivially, properly aligned
// - the region of memory beginning at `src` with a size of `src.len()`
// bytes does not overlap with the region of memory beginning at `dst`
// with the same size, because `dst` is derived from an exclusive
// reference.
unsafe {
core::ptr::copy_nonoverlapping(src.as_ptr(), dst.as_mut_ptr(), src.len());
};
}
/// Unsafely transmutes the given `src` into a type `Dst`.
///
/// # Safety
///
/// The value `src` must be a valid instance of `Dst`.
#[inline(always)]
pub(crate) const unsafe fn transmute_unchecked<Src, Dst>(src: Src) -> Dst {
static_assert!(Src, Dst => core::mem::size_of::<Src>() == core::mem::size_of::<Dst>());
#[repr(C)]
union Transmute<Src, Dst> {
src: ManuallyDrop<Src>,
dst: ManuallyDrop<Dst>,
}
// SAFETY: Since `Transmute<Src, Dst>` is `#[repr(C)]`, its `src` and `dst`
// fields both start at the same offset and the types of those fields are
// transparent wrappers around `Src` and `Dst` [1]. Consequently,
// initializing `Transmute` with with `src` and then reading out `dst` is
// equivalent to transmuting from `Src` to `Dst` [2]. Transmuting from `src`
// to `Dst` is valid because — by contract on the caller — `src` is a valid
// instance of `Dst`.
//
// [1] Per https://doc.rust-lang.org/1.82.0/std/mem/struct.ManuallyDrop.html:
//
// `ManuallyDrop<T>` is guaranteed to have the same layout and bit
// validity as `T`, and is subject to the same layout optimizations as
// `T`.
//
// [2] Per https://doc.rust-lang.org/1.82.0/reference/items/unions.html#reading-and-writing-union-fields:
//
// Effectively, writing to and then reading from a union with the C
// representation is analogous to a transmute from the type used for
// writing to the type used for reading.
unsafe { ManuallyDrop::into_inner(Transmute { src: ManuallyDrop::new(src) }.dst) }
}
/// # Safety
///
/// `Src` must have a greater or equal alignment to `Dst`.
pub(crate) unsafe fn transmute_ref<Src, Dst, R>(src: &Src) -> &Dst
where
Src: ?Sized,
Dst: SizeEq<Src>
+ TransmuteFromPtr<Src, Shared, Valid, Valid, <Dst as SizeEq<Src>>::CastFrom, R>
+ ?Sized,
{
let dst = Ptr::from_ref(src).transmute();
// SAFETY: The caller promises that `Src`'s alignment is at least as large
// as `Dst`'s alignment.
let dst = unsafe { dst.assume_alignment() };
dst.as_ref()
}
/// # Safety
///
/// `Src` must have a greater or equal alignment to `Dst`.
pub(crate) unsafe fn transmute_mut<Src, Dst, R>(src: &mut Src) -> &mut Dst
where
Src: ?Sized,
Dst: SizeEq<Src>
+ TransmuteFromPtr<Src, Exclusive, Valid, Valid, <Dst as SizeEq<Src>>::CastFrom, R>
+ ?Sized,
{
let dst = Ptr::from_mut(src).transmute();
// SAFETY: The caller promises that `Src`'s alignment is at least as large
// as `Dst`'s alignment.
let dst = unsafe { dst.assume_alignment() };
dst.as_mut()
}
/// Uses `allocate` to create a `Box<T>`.
///
/// # Errors
///
/// Returns an error on allocation failure. Allocation failure is guaranteed
/// never to cause a panic or an abort.
///
/// # Safety
///
/// `allocate` must be either `alloc::alloc::alloc` or
/// `alloc::alloc::alloc_zeroed`. The referent of the box returned by `new_box`
/// has the same bit-validity as the referent of the pointer returned by the
/// given `allocate` and sufficient size to store `T` with `meta`.
#[must_use = "has no side effects (other than allocation)"]
#[cfg(feature = "alloc")]
#[inline]
pub(crate) unsafe fn new_box<T>(
meta: T::PointerMetadata,
allocate: unsafe fn(core::alloc::Layout) -> *mut u8,
) -> Result<alloc::boxed::Box<T>, AllocError>
where
T: ?Sized + crate::KnownLayout,
{
let align = T::LAYOUT.align.get();
if !T::is_valid_metadata(meta) {
return Err(AllocError);
}
let size = match T::size_for_metadata(meta) {
Some(size) => size,
// Thanks to the `!T::is_valid_metadata(meta)` check
// above, this branch is unreachable. Fortunately, the
// optimizer recognizes this, so replacing this branch
// with `unreachable_unchecked` produces no codegen
// improvements.
None => return Err(AllocError),
};
let ptr = if size != 0 {
// SAFETY:
// - `align` is derived from a `NonZeroUsize` and is thus non-zero.
// - `align` is a power of two because, by invariant on
// `KnownLayout::LAYOUT` `<T as KnownLayout>::LAYOUT` accurately
// reflects the layout of `T`.
// - `size`, by invariant on `size_for_metadata` is well-aligned for
// `align` and, by the check on `T::is_valid_metadata(meta)`, is less
// than `isize::MAX`.
let layout: Layout = unsafe { Layout::from_size_align_unchecked(size, align) };
// SAFETY: By contract on the caller, `allocate` is either
// `alloc::alloc::alloc` or `alloc::alloc::alloc_zeroed`. The above
// check ensures their shared safety precondition: that the supplied
// layout is not zero-sized type [1].
//
// [1] Per https://doc.rust-lang.org/1.81.0/std/alloc/trait.GlobalAlloc.html#tymethod.alloc:
//
// This function is unsafe because undefined behavior can result if
// the caller does not ensure that layout has non-zero size.
let ptr = unsafe { allocate(layout) };
match NonNull::new(ptr) {
Some(ptr) => ptr,
None => return Err(AllocError),
}
} else {
// We use `transmute` instead of an `as` cast since Miri (with strict
// provenance enabled) notices and complains that an `as` cast creates a
// pointer with no provenance. Miri isn't smart enough to realize that
// we're only executing this branch when we're constructing a zero-sized
// `Box`, which doesn't require provenance.
//
// SAFETY: any initialized bit sequence is a bit-valid `*mut u8`. All
// bits of a `usize` are initialized.
//
// `#[allow(unknown_lints)]` is for `integer_to_ptr_transmutes`
#[allow(unknown_lints)]
#[allow(clippy::useless_transmute, integer_to_ptr_transmutes)]
let dangling = unsafe { mem::transmute::<usize, *mut u8>(align) };
// SAFETY: `dangling` is constructed from `align`, which is derived from
// a `NonZeroUsize`, which is guaranteed to be non-zero.
//
// `Box<[T]>` does not allocate when `T` is zero-sized or when `len` is
// zero, but it does require a non-null dangling pointer for its
// allocation.
//
// FIXME(https://github.com/rust-lang/rust/issues/95228): Use
// `std::ptr::without_provenance` once it's stable. That may optimize
// better. As written, Rust may assume that this consumes "exposed"
// provenance, and thus Rust may have to assume that this may consume
// provenance from any pointer whose provenance has been exposed.
unsafe { NonNull::new_unchecked(dangling) }
};
let ptr = T::raw_from_ptr_len(ptr, meta);
// FIXME(#429): Add a "SAFETY" comment and remove this `allow`. Make sure to
// include a justification that `ptr.as_ptr()` is validly-aligned in the ZST
// case (in which we manually construct a dangling pointer) and to justify
// why `Box` is safe to drop (it's because `allocate` uses the system
// allocator).
#[allow(clippy::undocumented_unsafe_blocks)]
Ok(unsafe { alloc::boxed::Box::from_raw(ptr.as_ptr()) })
}
mod len_of {
use super::*;
/// A witness type for metadata of a valid instance of `&T`.
pub struct MetadataOf<T: ?Sized + KnownLayout> {
/// # Safety
///
/// The size of an instance of `&T` with the given metadata is not
/// larger than `isize::MAX`.
meta: T::PointerMetadata,
_p: PhantomData<T>,
}
impl<T: ?Sized + KnownLayout> Copy for MetadataOf<T> {}
impl<T: ?Sized + KnownLayout> Clone for MetadataOf<T> {
#[inline]
fn clone(&self) -> Self {
*self
}
}
impl<T: ?Sized + KnownLayout> core::fmt::Debug for MetadataOf<T>
where
T::PointerMetadata: core::fmt::Debug,
{
#[inline]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("MetadataOf").field("meta", &self.meta).finish()
}
}
impl<T: ?Sized> MetadataOf<T>
where
T: KnownLayout,
{
/// Returns `None` if `meta` is greater than `t`'s metadata.
#[inline(always)]
pub(crate) fn new_in_bounds(t: &T, meta: usize) -> Option<Self>
where
T: KnownLayout<PointerMetadata = usize>,
{
if meta <= Ptr::from_ref(t).len() {
// SAFETY: We have checked that `meta` is not greater than `t`'s
// metadata, which, by invariant on `&T`, addresses no more than
// `isize::MAX` bytes [1][2].
//
// [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:
//
// * `t` is non-null
// * `t` is aligned to `align_of_val(t)`
// * 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.
//
// [2] 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:
// - For all addresses `a` in `addresses`, `a` is in the
// range `base .. (base + size)` (note that this requires
// `a < base + size`, not `a <= base + size`)
// - `base` is not equal to [`null()`] (i.e., the address
// with the numerical value 0)
// - `base + size <= usize::MAX`
// - `size <= isize::MAX`
Some(unsafe { Self::new_unchecked(meta) })
} else {
None
}
}
/// # Safety
///
/// The size of an instance of `&T` with the given metadata is not
/// larger than `isize::MAX`.
pub(crate) unsafe fn new_unchecked(meta: T::PointerMetadata) -> Self {
// SAFETY: The caller has promised that the size of an instance of
// `&T` with the given metadata is not larger than `isize::MAX`.
Self { meta, _p: PhantomData }
}
pub(crate) fn get(&self) -> T::PointerMetadata
where
T::PointerMetadata: Copy,
{
self.meta
}
#[inline]
pub(crate) fn padding_needed_for(&self) -> usize
where
T: KnownLayout<PointerMetadata = usize>,
{
let trailing_slice_layout = crate::trailing_slice_layout::<T>();
// FIXME(#67): Remove this allow. See NumExt for more details.
#[allow(
unstable_name_collisions,
clippy::incompatible_msrv,
clippy::multiple_unsafe_ops_per_block
)]
// SAFETY: By invariant on `self`, a `&T` with metadata `self.meta`
// describes an object of size `<= isize::MAX`. This computes the
// size of such a `&T` without any trailing padding, and so neither
// the multiplication nor the addition will overflow.
let unpadded_size = unsafe {
let trailing_size = self.meta.unchecked_mul(trailing_slice_layout.elem_size);
trailing_size.unchecked_add(trailing_slice_layout.offset)
};
util::padding_needed_for(unpadded_size, T::LAYOUT.align)
}
#[inline(always)]
pub(crate) fn validate_cast_and_convert_metadata(
addr: usize,
bytes_len: MetadataOf<[u8]>,
cast_type: CastType,
meta: Option<T::PointerMetadata>,
) -> Result<(MetadataOf<T>, MetadataOf<[u8]>), MetadataCastError> {
let layout = match meta {
None => T::LAYOUT,
// This can return `Err(MetadataCastError::Size)` if the
// metadata describes an object which can't fit in an `isize`.
Some(meta) => {
if !T::is_valid_metadata(meta) {
return Err(MetadataCastError::Size);
}
let size = match T::size_for_metadata(meta) {
Some(size) => size,
// Thanks to the `!T::is_valid_metadata(meta)` check
// above, this branch is unreachable. Fortunately, the
// optimizer recognizes this, so replacing this branch
// with `unreachable_unchecked` produces no codegen
// improvements.
None => return Err(MetadataCastError::Size),
};
DstLayout {
align: T::LAYOUT.align,
size_info: crate::SizeInfo::Sized { size },
statically_shallow_unpadded: false,
}
}
};
// Lemma 0: By contract on `validate_cast_and_convert_metadata`, if
// the result is `Ok(..)`, then a `&T` with `elems` trailing slice
// elements is no larger in size than `bytes_len.get()`.
let (elems, split_at) =
layout.validate_cast_and_convert_metadata(addr, bytes_len.get(), cast_type)?;
let elems = T::PointerMetadata::from_elem_count(elems);
// For a slice DST type, if `meta` is `Some(elems)`, then we
// synthesize `layout` to describe a sized type whose size is equal
// to the size of the instance that we are asked to cast. For sized
// types, `validate_cast_and_convert_metadata` returns `elems == 0`.
// Thus, in this case, we need to use the `elems` passed by the
// caller, not the one returned by
// `validate_cast_and_convert_metadata`.
//
// Lemma 1: A `&T` with `elems` trailing slice elements is no larger
// in size than `bytes_len.get()`. Proof:
// - If `meta` is `None`, then `elems` satisfies this condition by
// Lemma 0.
// - If `meta` is `Some(meta)`, then `layout` describes an object
// whose size is equal to the size of an `&T` with `meta`
// metadata. By Lemma 0, that size is not larger than
// `bytes_len.get()`.
//
// Lemma 2: A `&T` with `elems` trailing slice elements is no larger
// than `isize::MAX` bytes. Proof: By Lemma 1, a `&T` with metadata
// `elems` is not larger in size than `bytes_len.get()`. By
// invariant on `MetadataOf<[u8]>`, a `&[u8]` with metadata
// `bytes_len` is not larger than `isize::MAX`. Because
// `size_of::<u8>()` is `1`, a `&[u8]` with metadata `bytes_len` has
// size `bytes_len.get()` bytes. Therefore, a `&T` with metadata
// `elems` has size not larger than `isize::MAX`.
let elems = meta.unwrap_or(elems);
// SAFETY: See Lemma 2.
let elems = unsafe { MetadataOf::new_unchecked(elems) };
// SAFETY: Let `size` be the size of a `&T` with metadata `elems`.
// By post-condition on `validate_cast_and_convert_metadata`, one of
// the following conditions holds:
// - `split_at == size`, in which case, by Lemma 2, `split_at <=
// isize::MAX`. Since `size_of::<u8>() == 1`, a `[u8]` with
// `split_at` elems has size not larger than `isize::MAX`.
// - `split_at == bytes_len - size`. Since `bytes_len:
// MetadataOf<u8>`, and since `size` is non-negative, `split_at`
// addresses no more bytes than `bytes_len` does. Since
// `bytes_len: MetadataOf<u8>`, `bytes_len` describes a `[u8]`
// which has no more than `isize::MAX` bytes, and thus so does
// `split_at`.
let split_at = unsafe { MetadataOf::<[u8]>::new_unchecked(split_at) };
Ok((elems, split_at))
}
}
}
pub use len_of::MetadataOf;
/// Since we support multiple versions of Rust, there are often features which
/// have been stabilized in the most recent stable release which do not yet
/// exist (stably) on our MSRV. This module provides polyfills for those
/// features so that we can write more "modern" code, and just remove the
/// polyfill once our MSRV supports the corresponding feature. Without this,
/// we'd have to write worse/more verbose code and leave FIXME comments
/// sprinkled throughout the codebase to update to the new pattern once it's
/// stabilized.
///
/// Each trait is imported as `_` at the crate root; each polyfill should "just
/// work" at usage sites.
pub(crate) mod polyfills {
use core::ptr::{self, NonNull};
// A polyfill for `NonNull::slice_from_raw_parts` that we can use before our
// MSRV is 1.70, when that function was stabilized.
//
// The `#[allow(unused)]` is necessary because, on sufficiently recent
// toolchain versions, `ptr.slice_from_raw_parts()` resolves to the inherent
// method rather than to this trait, and so this trait is considered unused.
//
// FIXME(#67): Once our MSRV is 1.70, remove this.
#[allow(unused)]
pub(crate) trait NonNullExt<T> {
fn slice_from_raw_parts(data: Self, len: usize) -> NonNull<[T]>;
}
impl<T> NonNullExt<T> for NonNull<T> {
// NOTE on coverage: this will never be tested in nightly since it's a
// polyfill for a feature which has been stabilized on our nightly
// toolchain.
#[cfg_attr(
all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS),
coverage(off)
)]
#[inline(always)]
fn slice_from_raw_parts(data: Self, len: usize) -> NonNull<[T]> {
let ptr = ptr::slice_from_raw_parts_mut(data.as_ptr(), len);
// SAFETY: `ptr` is converted from `data`, which is non-null.
unsafe { NonNull::new_unchecked(ptr) }
}
}
// A polyfill for `Self::unchecked_sub` that we can use until methods like
// `usize::unchecked_sub` is stabilized.
//
// The `#[allow(unused)]` is necessary because, on sufficiently recent
// toolchain versions, `ptr.slice_from_raw_parts()` resolves to the inherent
// method rather than to this trait, and so this trait is considered unused.
//
// FIXME(#67): Once our MSRV is high enough, remove this.
#[allow(unused)]
pub(crate) trait NumExt {
/// Add without checking for overflow.
///
/// # Safety
///
/// The caller promises that the addition will not overflow.
unsafe fn unchecked_add(self, rhs: Self) -> Self;
/// Subtract without checking for underflow.
///
/// # Safety
///
/// The caller promises that the subtraction will not underflow.
unsafe fn unchecked_sub(self, rhs: Self) -> Self;
/// Multiply without checking for overflow.
///
/// # Safety
///
/// The caller promises that the multiplication will not overflow.
unsafe fn unchecked_mul(self, rhs: Self) -> Self;
}
// NOTE on coverage: these will never be tested in nightly since they're
// polyfills for a feature which has been stabilized on our nightly
// toolchain.
impl NumExt for usize {
#[cfg_attr(
all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS),
coverage(off)
)]
#[inline(always)]
unsafe fn unchecked_add(self, rhs: usize) -> usize {
match self.checked_add(rhs) {
Some(x) => x,
None => {
// SAFETY: The caller promises that the addition will not
// underflow.
unsafe { core::hint::unreachable_unchecked() }
}
}
}
#[cfg_attr(
all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS),
coverage(off)
)]
#[inline(always)]
unsafe fn unchecked_sub(self, rhs: usize) -> usize {
match self.checked_sub(rhs) {
Some(x) => x,
None => {
// SAFETY: The caller promises that the subtraction will not
// underflow.
unsafe { core::hint::unreachable_unchecked() }
}
}
}
#[cfg_attr(
all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS),
coverage(off)
)]
#[inline(always)]
unsafe fn unchecked_mul(self, rhs: usize) -> usize {
match self.checked_mul(rhs) {
Some(x) => x,
None => {
// SAFETY: The caller promises that the multiplication will
// not overflow.
unsafe { core::hint::unreachable_unchecked() }
}
}
}
}
}
#[cfg(test)]
pub(crate) mod testutil {
use crate::*;
/// A `T` which is aligned to at least `align_of::<A>()`.
#[derive(Default)]
pub(crate) struct Align<T, A> {
pub(crate) t: T,
_a: [A; 0],
}
impl<T: Default, A> Align<T, A> {
pub(crate) fn set_default(&mut self) {
self.t = T::default();
}
}
impl<T, A> Align<T, A> {
pub(crate) const fn new(t: T) -> Align<T, A> {
Align { t, _a: [] }
}
}
/// A `T` which is guaranteed not to satisfy `align_of::<A>()`.
///
/// It must be the case that `align_of::<T>() < align_of::<A>()` in order
/// for this type to work properly.
#[repr(C)]
pub(crate) struct ForceUnalign<T: Unaligned, A> {
// The outer struct is aligned to `A`, and, thanks to `repr(C)`, `t` is
// placed at the minimum offset that guarantees its alignment. If
// `align_of::<T>() < align_of::<A>()`, then that offset will be
// guaranteed *not* to satisfy `align_of::<A>()`.
//
// Note that we need `T: Unaligned` in order to guarantee that there is
// no padding between `_u` and `t`.
_u: u8,
pub(crate) t: T,
_a: [A; 0],
}
impl<T: Unaligned, A> ForceUnalign<T, A> {
pub(crate) fn new(t: T) -> ForceUnalign<T, A> {
ForceUnalign { _u: 0, t, _a: [] }
}
}
// A `u64` with alignment 8.
//
// Though `u64` has alignment 8 on some platforms, it's not guaranteed. By
// contrast, `AU64` is guaranteed to have alignment 8 on all platforms.
#[derive(
KnownLayout,
Immutable,
FromBytes,
IntoBytes,
Eq,
PartialEq,
Ord,
PartialOrd,
Default,
Debug,
Copy,
Clone,
)]
#[repr(C, align(8))]
pub(crate) struct AU64(pub(crate) u64);
impl AU64 {
// Converts this `AU64` to bytes using this platform's endianness.
pub(crate) fn to_bytes(self) -> [u8; 8] {
crate::transmute!(self)
}
}
impl Display for AU64 {
#[cfg_attr(
all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS),
coverage(off)
)]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
Display::fmt(&self.0, f)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_round_down_to_next_multiple_of_alignment() {
fn alt_impl(n: usize, align: NonZeroUsize) -> usize {
let mul = n / align.get();
mul * align.get()
}
for align in [1, 2, 4, 8, 16] {
for n in 0..256 {
let align = NonZeroUsize::new(align).unwrap();
let want = alt_impl(n, align);
let got = round_down_to_next_multiple_of_alignment(n, align);
assert_eq!(got, want, "round_down_to_next_multiple_of_alignment({}, {})", n, align);
}
}
}
#[rustversion::since(1.57.0)]
#[test]
#[should_panic]
fn test_round_down_to_next_multiple_of_alignment_zerocopy_panic_in_const_and_vec_try_reserve() {
round_down_to_next_multiple_of_alignment(0, NonZeroUsize::new(3).unwrap());
}
#[test]
fn test_send_sync_phantom_data() {
let x = SendSyncPhantomData::<u8>::default();
let y = x.clone();
assert!(x == y);
assert!(x == SendSyncPhantomData::<u8>::default());
}
#[test]
#[allow(clippy::as_conversions)]
fn test_as_address() {
let x = 0u8;
let r = &x;
let mut x_mut = 0u8;
let rm = &mut x_mut;
let p = r as *const u8;
let pm = rm as *mut u8;
let nn = NonNull::new(p as *mut u8).unwrap();
assert_eq!(AsAddress::addr(r), p as usize);
assert_eq!(AsAddress::addr(rm), pm as usize);
assert_eq!(AsAddress::addr(p), p as usize);
assert_eq!(AsAddress::addr(pm), pm as usize);
assert_eq!(AsAddress::addr(nn), p as usize);
}
}
File diff suppressed because it is too large Load Diff