Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial commit of Ptr type #406

Merged
merged 2 commits into from
Oct 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ env:
# `ZC_NIGHTLY_XXX` are flags that we add to `XXX` only on the nightly
# toolchain.
ZC_NIGHTLY_RUSTFLAGS: -Zrandomize-layout
ZC_NIGHTLY_MIRIFLAGS: "-Zmiri-symbolic-alignment-check -Zmiri-strict-provenance -Zmiri-backtrace=full"
ZC_NIGHTLY_MIRIFLAGS: "-Zmiri-strict-provenance -Zmiri-backtrace=full"

jobs:
build_test:
Expand Down
39 changes: 35 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -247,17 +247,27 @@ use core::{
NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize, Wrapping,
},
ops::{Deref, DerefMut},
ptr, slice,
ptr::{self, NonNull},
slice,
};

#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "alloc")]
use {
alloc::{boxed::Box, vec::Vec},
core::{alloc::Layout, ptr::NonNull},
core::alloc::Layout,
};

// For each 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::NonNullExt as _;

// This is a hack to allow zerocopy-derive derives to work in this crate. They
// assume that zerocopy is linked as an extern crate, so they access items from
// it as `zerocopy::Xxx`. This makes that still work.
Expand Down Expand Up @@ -352,8 +362,11 @@ impl SizeInfo {
}
}

#[cfg_attr(test, derive(Copy, Clone, Debug))]
enum _CastType {
#[doc(hidden)]
#[derive(Copy, Clone)]
#[cfg_attr(test, derive(Debug))]
#[allow(missing_debug_implementations)]
pub enum _CastType {
_Prefix,
_Suffix,
}
Expand Down Expand Up @@ -458,6 +471,9 @@ impl DstLayout {
///
/// # Panics
///
/// `validate_cast_and_convert_metadata` will panic if `self` describes a
/// DST whose trailing slice element is zero-sized.
///
/// If `addr + bytes_len` overflows `usize`,
/// `validate_cast_and_convert_metadata` may panic, or it may return
/// incorrect results. No guarantees are made about when
Expand Down Expand Up @@ -625,12 +641,27 @@ impl DstLayout {
pub unsafe trait KnownLayout: sealed::KnownLayoutSealed {
#[doc(hidden)]
const LAYOUT: DstLayout;

/// SAFETY: The returned pointer has the same address and provenance as
/// `bytes`. If `Self` is a DST, the returned pointer's referent has `elems`
/// elements in its trailing slice. If `Self` is sized, `elems` is ignored.
#[doc(hidden)]
fn raw_from_ptr_len(bytes: NonNull<u8>, elems: usize) -> NonNull<Self>;
}

impl<T: KnownLayout> sealed::KnownLayoutSealed for [T] {}
// SAFETY: Delegates safety to `DstLayout::for_slice`.
unsafe impl<T: KnownLayout> KnownLayout for [T] {
const LAYOUT: DstLayout = DstLayout::for_slice::<T>();

// SAFETY: `.cast` preserves address and provenance. The returned pointer
// refers to an object with `elems` elements by construction.
#[inline(always)]
fn raw_from_ptr_len(data: NonNull<u8>, elems: usize) -> NonNull<Self> {
// TODO(#67): Remove this allow. See NonNullExt for more details.
#[allow(unstable_name_collisions)]
NonNull::slice_from_raw_parts(data.cast::<T>(), elems)
}
}

#[rustfmt::skip]
Expand Down
49 changes: 40 additions & 9 deletions src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,11 +204,24 @@ macro_rules! impl_known_layout {
};
($($ty:ty),*) => { $(impl_known_layout!(@inner , => $ty);)* };
(@inner $(const $constvar:ident : $constty:ty)? , $($tyvar:ident $(: ?$optbound:ident)?)? => $ty:ty) => {
impl<$(const $constvar : $constty,)? $($tyvar $(: ?$optbound)?)?> sealed::KnownLayoutSealed for $ty {}
// SAFETY: Delegates safety to `DstLayout::for_type`.
unsafe impl<$(const $constvar : $constty,)? $($tyvar $(: ?$optbound)?)?> KnownLayout for $ty {
const LAYOUT: DstLayout = DstLayout::for_type::<$ty>();
}
const _: () = {
use core::ptr::NonNull;

impl<$(const $constvar : $constty,)? $($tyvar $(: ?$optbound)?)?> sealed::KnownLayoutSealed for $ty {}
// SAFETY: Delegates safety to `DstLayout::for_type`.
unsafe impl<$(const $constvar : $constty,)? $($tyvar $(: ?$optbound)?)?> KnownLayout for $ty {
const LAYOUT: DstLayout = DstLayout::for_type::<$ty>();

// SAFETY: `.cast` preserves address and provenance.
joshlf marked this conversation as resolved.
Show resolved Hide resolved
//
// TODO(#429): Add documentation to `.cast` that promises that
// it preserves provenance.
#[inline(always)]
fn raw_from_ptr_len(bytes: NonNull<u8>, _elems: usize) -> NonNull<Self> {
bytes.cast::<Self>()
}
}
};
};
}

Expand All @@ -225,10 +238,28 @@ macro_rules! impl_known_layout {
/// and this operation must preserve referent size (ie, `size_of_val_raw`).
macro_rules! unsafe_impl_known_layout {
($($tyvar:ident: ?Sized + KnownLayout =>)? #[repr($repr:ty)] $ty:ty) => {
impl<$($tyvar: ?Sized + KnownLayout)?> sealed::KnownLayoutSealed for $ty {}
unsafe impl<$($tyvar: ?Sized + KnownLayout)?> KnownLayout for $ty {
const LAYOUT: DstLayout = <$repr as KnownLayout>::LAYOUT;
}
const _: () = {
use core::ptr::NonNull;

impl<$($tyvar: ?Sized + KnownLayout)?> sealed::KnownLayoutSealed for $ty {}
unsafe impl<$($tyvar: ?Sized + KnownLayout)?> KnownLayout for $ty {
const LAYOUT: DstLayout = <$repr as KnownLayout>::LAYOUT;

// SAFETY: All operations preserve address and provenance.
// Caller has promised that the `as` cast preserves size.
//
// TODO(#429): Add documentation to `NonNull::new_unchecked`
// that it preserves provenance.
#[inline(always)]
#[allow(unused_qualifications)] // for `core::ptr::NonNull`
fn raw_from_ptr_len(bytes: NonNull<u8>, elems: usize) -> NonNull<Self> {
#[allow(clippy::as_conversions)]
let ptr = <$repr>::raw_from_ptr_len(bytes, elems).as_ptr() as *mut Self;
// SAFETY: `ptr` was converted from `bytes`, which is non-null.
unsafe { NonNull::new_unchecked(ptr) }
}
}
};
};
}

Expand Down
Loading