Skip to content
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
95 changes: 45 additions & 50 deletions zerocopy/src/impls.rs

Large diffs are not rendered by default.

32 changes: 16 additions & 16 deletions zerocopy/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -411,7 +411,7 @@ use core::alloc::Layout;
// Used by `KnownLayout`.
#[doc(hidden)]
pub use crate::layout::*;
// Used by `TryFromBytes::is_bit_valid`.
// Used by `TryFromBytes::is_safe`.
#[doc(hidden)]
pub use crate::pointer::{invariant::BecauseImmutable, Maybe, Ptr};
// For each trait polyfill, as soon as the corresponding feature is stable, the
Expand Down Expand Up @@ -1430,9 +1430,9 @@ where
// type – the type itself is irrelevant.
ValidityKind::Uninit | ValidityKind::Initialized => true,
// The projectability of an enum field from an
// `AsInitialized` or `Valid` state is a dynamic
// `AsInitialized` or `Safe` state is a dynamic
// property of its tag.
ValidityKind::AsInitialized | ValidityKind::Valid => false,
ValidityKind::AsInitialized | ValidityKind::Safe => false,
}
}
};
Expand Down Expand Up @@ -1848,25 +1848,25 @@ pub unsafe trait TryFromBytes {
///
/// # Safety
///
/// Unsafe code may assume that, if `is_bit_valid(candidate)` returns true,
/// Unsafe code may assume that, if `is_safe(candidate)` returns true,
/// `*candidate` contains a valid `Self`.
///
/// # Panics
///
/// `is_bit_valid` may panic. Callers are responsible for ensuring that any
/// `unsafe` code remains sound even in the face of `is_bit_valid`
/// panicking. (We support user-defined validation routines; so long as
/// these routines are not required to be `unsafe`, there is no way to
/// ensure that these do not generate panics.)
/// `is_safe` may panic. Callers are responsible for ensuring that any
/// `unsafe` code remains sound even in the face of `is_safe` panicking. (We
/// support user-defined validation routines; so long as these routines are
/// not required to be `unsafe`, there is no way to ensure that these do not
/// generate panics.)
///
/// Besides user-defined validation routines panicking, `is_bit_valid` will
/// either panic or fail to compile if called on a pointer with [`Shared`]
/// aliasing when `Self: !Immutable`.
/// Besides user-defined validation routines panicking, `is_safe` will either
/// panic or fail to compile if called on a pointer with [`Shared`] aliasing
/// when `Self: !Immutable`.
///
/// [`UnsafeCell`]: core::cell::UnsafeCell
/// [`Shared`]: invariant::Shared
#[doc(hidden)]
fn is_bit_valid<A>(candidate: Maybe<'_, Self, A>) -> bool
fn is_safe<A>(candidate: Maybe<'_, Self, A>) -> bool
where
A: invariant::Alignment;

Expand Down Expand Up @@ -3460,14 +3460,14 @@ unsafe fn try_read_from<S, T: TryFromBytes>(
// This call may panic. If that happens, it doesn't cause any soundness
// issues, as we have not generated any invalid state which we need to fix
// before returning.
if !Wrapping::<T>::is_bit_valid(c_ptr.reborrow_shared().forget_aligned()) {
if !Wrapping::<T>::is_safe(c_ptr.reborrow_shared().forget_aligned()) {
return Err(ValidityError::new(source).into());
}

fn _assert_same_size_and_validity<T>()
where
Wrapping<T>: pointer::TransmuteFrom<T, invariant::Valid, invariant::Valid>,
T: pointer::TransmuteFrom<Wrapping<T>, invariant::Valid, invariant::Valid>,
Wrapping<T>: pointer::TransmuteFrom<T, invariant::Safe, invariant::Safe>,
T: pointer::TransmuteFrom<Wrapping<T>, invariant::Safe, invariant::Safe>,
{
}

Expand Down
4 changes: 2 additions & 2 deletions zerocopy/src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1033,7 +1033,7 @@ macro_rules! cryptocorrosion_derive_traits {
)?
{
#[inline(always)]
fn is_bit_valid<A>(_: $crate::Maybe<'_, Self, A>) -> bool
fn is_safe<A>(_: $crate::Maybe<'_, Self, A>) -> bool
where
A: $crate::invariant::Alignment,
{
Expand Down Expand Up @@ -1179,7 +1179,7 @@ macro_rules! cryptocorrosion_derive_traits {
)*
{
#[inline(always)]
fn is_bit_valid<A>(_: $crate::Maybe<'_, Self, A>) -> bool
fn is_safe<A>(_: $crate::Maybe<'_, Self, A>) -> bool
where
A: $crate::invariant::Alignment,
{
Expand Down
18 changes: 9 additions & 9 deletions zerocopy/src/pointer/invariant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ pub trait Alignment: Sealed {
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: Invariants<Alignment = Self, Validity = Safe>,
I::Aliasing: Reference;
}

Expand Down Expand Up @@ -101,7 +101,7 @@ pub enum ValidityKind {
Uninit,
AsInitialized,
Initialized,
Valid,
Safe,
}

/// An [`Aliasing`] invariant which is either [`Shared`] or [`Exclusive`].
Expand Down Expand Up @@ -147,7 +147,7 @@ impl Alignment for Unaligned {
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: Invariants<Alignment = Self, Validity = Safe>,
I::Aliasing: Reference,
{
(*ptr.into_unalign().as_ref()).into_inner()
Expand All @@ -162,7 +162,7 @@ impl Alignment for Aligned {
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: Invariants<Alignment = Self, Validity = Safe>,
I::Aliasing: Reference,
{
*ptr.as_ref()
Expand Down Expand Up @@ -227,11 +227,11 @@ unsafe impl Validity for 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
pub enum Safe {}
// SAFETY: `Safe`'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;
unsafe impl Validity for Safe {
const KIND: ValidityKind = ValidityKind::Safe;
}

/// # Safety
Expand Down Expand Up @@ -289,7 +289,7 @@ mod sealed {
impl Sealed for Uninit {}
impl Sealed for AsInitialized {}
impl Sealed for Initialized {}
impl Sealed for Valid {}
impl Sealed for Safe {}

impl<A: Sealed, AA: Sealed, V: Sealed> Sealed for (A, AA, V) {}

Expand Down
4 changes: 2 additions & 2 deletions zerocopy/src/pointer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ 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`].
/// to [`TryFromBytes::is_safe`].
///
/// [`TryFromBytes::is_bit_valid`]: crate::TryFromBytes::is_bit_valid
/// [`TryFromBytes::is_safe`]: crate::TryFromBytes::is_safe
pub type Maybe<'a, T, Alignment = invariant::Unaligned> =
Ptr<'a, ReadOnly<T>, (invariant::Shared, Alignment, invariant::Initialized)>;

Expand Down
86 changes: 42 additions & 44 deletions zerocopy/src/pointer/ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ mod _conversions {
use crate::pointer::cast::{CastExact, CastSized, IdCast};

/// `&'a T` β†’ `Ptr<'a, T>`
impl<'a, T> Ptr<'a, T, (Shared, Aligned, Valid)>
impl<'a, T> Ptr<'a, T, (Shared, Aligned, Safe)>
where
T: 'a + ?Sized,
{
Expand All @@ -183,20 +183,19 @@ mod _conversions {
// 1. `ptr`, by invariant on `&'a T`, conforms to the alignment
// invariant of `Aligned`.
// 2. `ptr`'s referent, by invariant on `&'a T`, is a bit-valid `T`.
// This satisfies the requirement that a `Ptr<T, (_, _, Valid)>`
// This satisfies the requirement that a `Ptr<T, (_, _, Safe)>`
// point to a bit-valid `T`. Even if `T` permits interior
// mutation, this invariant guarantees that the returned `Ptr`
// can only ever be used to modify the referent to store
// bit-valid `T`s, which ensures that the returned `Ptr` cannot
// be used to violate the soundness of the original `ptr: &'a T`
// or of any other references that may exist to the same
// referent.
// mutation, this invariant guarantees that the returned `Ptr` can
// only ever be used to modify the referent to store bit-valid
// `T`s, which ensures that the returned `Ptr` cannot be used to
// violate the soundness of the original `ptr: &'a T` or of any
// other references that may exist to the same referent.
unsafe { Self::from_inner(inner) }
}
}

/// `&'a mut T` β†’ `Ptr<'a, T>`
impl<'a, T> Ptr<'a, T, (Exclusive, Aligned, Valid)>
impl<'a, T> Ptr<'a, T, (Exclusive, Aligned, Safe)>
where
T: 'a + ?Sized,
{
Expand All @@ -211,7 +210,7 @@ mod _conversions {
// invariant of `Aligned`.
// 2. `ptr`'s referent, by invariant on `&'a mut T`, is a bit-valid
// `T`. This satisfies the requirement that a `Ptr<T, (_, _,
// Valid)>` point to a bit-valid `T`. This invariant guarantees
// Safe)>` point to a bit-valid `T`. This invariant guarantees
// that the returned `Ptr` can only ever be used to modify the
// referent to store bit-valid `T`s, which ensures that the
// returned `Ptr` cannot be used to violate the soundness of the
Expand All @@ -224,7 +223,7 @@ mod _conversions {
impl<'a, T, I> Ptr<'a, T, I>
where
T: 'a + ?Sized,
I: Invariants<Alignment = Aligned, Validity = Valid>,
I: Invariants<Alignment = Aligned, Validity = Safe>,
I::Aliasing: Reference,
{
/// Converts `self` to a shared reference.
Expand Down Expand Up @@ -264,7 +263,7 @@ mod _conversions {
//
// 3. The pointer must point to a validly-initialized instance of
// `T`. This is ensured by-contract on `Ptr`, because the
// `I::Validity` is `Valid`.
// `I::Validity` is `Safe`.
//
// 4. You must enforce Rust’s aliasing rules. This is ensured by
// contract on `Ptr`, because `I::Aliasing: Reference`. Either it
Expand Down Expand Up @@ -377,7 +376,7 @@ mod _conversions {
}

/// `Ptr<'a, T>` β†’ `&'a mut T`
impl<'a, T> Ptr<'a, T, (Exclusive, Aligned, Valid)>
impl<'a, T> Ptr<'a, T, (Exclusive, Aligned, Safe)>
where
T: 'a + ?Sized,
{
Expand Down Expand Up @@ -413,8 +412,8 @@ mod _conversions {
// This is ensured by contract on all `PtrInner`s.
//
// 3. The pointer must point to a validly-initialized instance of
// `T`. This is ensured by-contract on `Ptr`, because the
// validity invariant is `Valid`.
// `T`. This is ensured by-contract on `Ptr`, because the validity
// invariant is `Safe`.
//
// 4. You must enforce Rust’s aliasing rules. This is ensured by
// contract on `Ptr`, because the `ALIASING_INVARIANT` is
Expand Down Expand Up @@ -562,7 +561,7 @@ mod _conversions {
// FIXME(#1359): This should be a `transmute_with` call.
// Unfortunately, to avoid blanket impl conflicts, we only implement
// `TransmuteFrom<T>` for `Unalign<T>` (and vice versa) specifically
// for `Valid` validity, not for all validity types.
// for `Safe` validity, not for all validity types.

// SAFETY:
// - By `CastSized: Cast`, `CastSized` preserves referent address,
Expand All @@ -589,7 +588,7 @@ mod _conversions {
impl<'a, T, I> Ptr<'a, T, I>
where
T: ?Sized,
I: Invariants<Validity = Valid>,
I: Invariants<Validity = Safe>,
I::Aliasing: Reference,
{
/// Reads the referent.
Expand Down Expand Up @@ -754,27 +753,27 @@ mod _transitions {
unsafe { self.assume_validity::<Initialized>() }
}

/// A shorthand for `self.assume_validity<Valid>()`.
/// A shorthand for `self.assume_validity<Safe>()`.
///
/// # Safety
///
/// The caller promises to uphold the safety preconditions of
/// `self.assume_validity<Valid>()`.
/// `self.assume_validity<Safe>()`.
#[must_use]
#[inline]
pub unsafe fn assume_valid(self) -> Ptr<'a, T, (I::Aliasing, I::Alignment, Valid)> {
pub unsafe fn assume_safe(self) -> Ptr<'a, T, (I::Aliasing, I::Alignment, Safe)> {
// SAFETY: The caller has promised to uphold the safety
// preconditions.
unsafe { self.assume_validity::<Valid>() }
unsafe { self.assume_validity::<Safe>() }
}

/// Checks that `self`'s referent is validly initialized for `T`,
/// returning a `Ptr` with `Valid` on success.
/// returning a `Ptr` with `Safe` on success.
///
/// # Panics
///
/// This method will panic if
/// [`T::is_bit_valid`][TryFromBytes::is_bit_valid] panics.
/// [`T::is_safe`][TryFromBytes::is_safe] panics.
///
/// # Safety
///
Expand All @@ -783,26 +782,25 @@ mod _transitions {
#[inline]
pub fn try_into_valid<R, S>(
mut self,
) -> Result<Ptr<'a, T, (I::Aliasing, I::Alignment, Valid)>, ValidityError<Self, T>>
) -> Result<Ptr<'a, T, (I::Aliasing, I::Alignment, Safe)>, ValidityError<Self, T>>
where
T: TryFromBytes
+ Read<I::Aliasing, R>
+ TryTransmuteFromPtr<T, I::Aliasing, I::Validity, Valid, IdCast, S>,
+ TryTransmuteFromPtr<T, I::Aliasing, I::Validity, Safe, IdCast, S>,
ReadOnly<T>: Read<I::Aliasing, R>,
I::Aliasing: Reference,
I: Invariants<Validity = Initialized>,
{
// This call may panic. If that happens, it doesn't cause any
// soundness issues, as we have not generated any invalid state
// which we need to fix before returning.
if T::is_bit_valid(self.reborrow().transmute::<_, _, _>().reborrow_shared()) {
// SAFETY: If `T::is_bit_valid`, code may assume that `self`
// contains a bit-valid instance of `T`. By `T:
// TryTransmuteFromPtr<T, I::Aliasing, I::Validity, Valid>`, so
// long as `self`'s referent conforms to the `Valid` validity
// for `T` (which we just confirmed), then this transmute is
// sound.
Ok(unsafe { self.assume_valid() })
if T::is_safe(self.reborrow().transmute::<_, _, _>().reborrow_shared()) {
// SAFETY: If `T::is_safe`, code may assume that `self` contains
// a bit-valid instance of `T`. By `T: TryTransmuteFromPtr<T,
// I::Aliasing, I::Validity, Safe>`, so long as `self`'s referent
// conforms to the `Safe` validity for `T` (which we just
// confirmed), then this transmute is sound.
Ok(unsafe { self.assume_safe() })
} else {
Err(ValidityError::new(self))
}
Expand Down Expand Up @@ -1039,11 +1037,11 @@ mod _casts {
#[allow(clippy::wrong_self_convention)]
#[must_use]
#[inline]
pub fn as_bytes<R>(self) -> Ptr<'a, [u8], (I::Aliasing, Aligned, Valid)>
pub fn as_bytes<R>(self) -> Ptr<'a, [u8], (I::Aliasing, Aligned, Safe)>
where
[u8]: TransmuteFromPtr<T, I::Aliasing, I::Validity, Valid, AsBytesCast, R>,
[u8]: TransmuteFromPtr<T, I::Aliasing, I::Validity, Safe, AsBytesCast, R>,
{
self.transmute_with::<[u8], Valid, AsBytesCast, _>().bikeshed_recall_aligned()
self.transmute_with::<[u8], Safe, AsBytesCast, _>().bikeshed_recall_aligned()
}
}

Expand Down Expand Up @@ -1095,7 +1093,7 @@ mod _casts {
/// alignment of `[u8]` is 1.
impl<'a, I> Ptr<'a, [u8], I>
where
I: Invariants<Validity = Valid>,
I: Invariants<Validity = Safe>,
{
/// Attempts to cast `self` to a `U` using the given cast type.
///
Expand Down Expand Up @@ -1159,22 +1157,22 @@ mod _casts {
// it is derived from `try_cast_into`, which promises that the
// object described by `target` is validly aligned for `U`.
// 2. By trait bound, `self` - and thus `target` - is a bit-valid
// `[u8]`. `Ptr<[u8], (_, _, Valid)>` and `Ptr<_, (_, _,
// `[u8]`. `Ptr<[u8], (_, _, Safe)>` and `Ptr<_, (_, _,
// Initialized)>` have the same bit validity, and so neither
// `self` nor `res` can be used to write a value to the referent
// which violates the other's validity invariant.
let res = unsafe { Ptr::from_inner(inner) };

// SAFETY:
// 0. `self` and `remainder` both have the type `[u8]`. Thus, they
// have `UnsafeCell`s at the same locations. Type casting does
// not affect aliasing.
// have `UnsafeCell`s at the same locations. Type casting does not
// affect aliasing.
// 1. `[u8]` has no alignment requirement.
// 2. `self` has validity `Valid` and has type `[u8]`. Since
// 2. `self` has validity `Safe` and has type `[u8]`. Since
// `remainder` references a subset of `self`'s referent, it is
// also a bit-valid `[u8]`. Thus, neither `self` nor `remainder`
// can be used to write a value to the referent which violates
// the other's validity invariant.
// can be used to write a value to the referent which violates the
// other's validity invariant.
let remainder = unsafe { Ptr::from_inner(remainder) };

Ok((res, remainder))
Expand Down Expand Up @@ -1370,7 +1368,7 @@ mod tests {
let _: Ptr<
'_,
<Enum as crate::HasTag<crate::project_clients::ProjectDerive>>::Tag,
(Shared, Aligned, Valid),
(Shared, Aligned, Safe),
> = Ptr::from_mut(&mut value).project_tag::<crate::project_clients::ProjectDerive>();
}

Expand Down
Loading
Loading