Skip to content
Closed
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
181 changes: 78 additions & 103 deletions src/impls.rs

Large diffs are not rendered by default.

16 changes: 15 additions & 1 deletion src/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -756,6 +756,20 @@ mod cast_from {
{
}

// SAFETY: FIXME(#1818, #2701): THIS IS UNSOUND. However, given how it's
// used today, it can't cause UB. In particular, the static assertions below
// only check that source alignment is not less than destination alignment,
// but not that they are equal. This means that a pointer cast could result
// in a referent with less trailing padding. This technically violates the
// safety invariant of `CastExact`, but can only result in UB if the padding
// bytes are read, which they never are. Obviously we should still fix this.
unsafe impl<Src, Dst> crate::pointer::cast::CastExact<Src, Dst> for CastFrom<Dst>
where
Src: KnownLayout<PointerMetadata = usize> + ?Sized,
Dst: KnownLayout<PointerMetadata = usize> + ?Sized,
{
}

// SAFETY: `project` produces a pointer which refers to the same referent
// bytes as its input, or to a subset of them (see inline comments for a
// more detailed proof of this). It does this using provenance-preserving
Expand All @@ -771,7 +785,7 @@ mod cast_from {
/// implement soundly.
//
// FIXME(#1817): Support Sized->Unsized and Unsized->Sized casts
fn project(src: PtrInner<'_, Src>) -> *mut Dst {
fn project_inner(src: PtrInner<'_, Src>) -> *mut Dst {
// At compile time (specifically, post-monomorphization time), we
// need to compute two things:
// - Whether, given *any* `*Src`, it is possible to construct a
Expand Down
6 changes: 3 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1566,7 +1566,7 @@ pub unsafe trait TryFromBytes {
/// [`UnsafeCell`]: core::cell::UnsafeCell
/// [`Shared`]: invariant::Shared
#[doc(hidden)]
fn is_bit_valid<A: invariant::Reference>(candidate: Maybe<'_, Self, A>) -> bool;
fn is_bit_valid(candidate: Maybe<'_, Self>) -> bool;

/// Attempts to interpret the given `source` as a `&Self`.
///
Expand Down Expand Up @@ -2974,7 +2974,7 @@ unsafe fn try_read_from<S, T: TryFromBytes>(
// via `c_ptr` so long as it is live, so we don't need to worry about the
// fact that `c_ptr` may have more restricted validity than `candidate`.
let c_ptr = unsafe { c_ptr.assume_validity::<invariant::Initialized>() };
let c_ptr = c_ptr.transmute();
let mut c_ptr = c_ptr.cast::<_, crate::pointer::cast::CastSized, _>();

// Since we don't have `T: KnownLayout`, we hack around that by using
// `Wrapping<T>`, which implements `KnownLayout` even if `T` doesn't.
Expand All @@ -2987,7 +2987,7 @@ unsafe fn try_read_from<S, T: TryFromBytes>(
// `try_into_valid` (and thus `is_bit_valid`) with a shared pointer when
// `Self: !Immutable`. Since `Self: Immutable`, this panic condition will
// not happen.
if !Wrapping::<T>::is_bit_valid(c_ptr.forget_aligned()) {
if !Wrapping::<T>::is_bit_valid(c_ptr.reborrow_shared().forget_aligned()) {
return Err(ValidityError::new(source).into());
}

Expand Down
12 changes: 4 additions & 8 deletions src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -895,10 +895,8 @@ macro_rules! cryptocorrosion_derive_traits {
$($field_ty: $crate::FromBytes,)*
)?
{
fn is_bit_valid<A>(_c: $crate::Maybe<'_, Self, A>) -> bool
where
A: $crate::pointer::invariant::Reference
{
#[inline]
fn is_bit_valid(_c: $crate::Maybe<'_, Self>) -> bool {
// SAFETY: This macro only accepts `#[repr(C)]` and
// `#[repr(transparent)]` structs, and this `impl` block
// requires all field types to be `FromBytes`. Thus, all
Expand Down Expand Up @@ -1038,10 +1036,8 @@ macro_rules! cryptocorrosion_derive_traits {
$field_ty: $crate::FromBytes,
)*
{
fn is_bit_valid<A>(_c: $crate::Maybe<'_, Self, A>) -> bool
where
A: $crate::pointer::invariant::Reference
{
#[inline]
fn is_bit_valid(_c: $crate::Maybe<'_, Self>) -> bool {
// SAFETY: This macro only accepts `#[repr(C)]` unions, and this
// `impl` block requires all field types to be `FromBytes`.
// Thus, all initialized byte sequences constitutes valid
Expand Down
32 changes: 2 additions & 30 deletions src/pointer/inner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,39 +176,11 @@ impl<'a, T: ?Sized> PtrInner<'a, T> {
unsafe { Self::new(ptr) }
}

/// # Safety
///
/// The caller may assume that the resulting `PtrInner` addresses a subset
/// of the bytes of `self`'s referent.
/// A shorthand for `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) }
C::project(self)
}
}

Expand Down
Loading
Loading