Skip to content

Commit 9c88adc

Browse files
committed
[pointer][WIP] Transmute
gherrit-pr-id: Iad14813bc6d933312bc8d7a1ddcf1aafc7126938
1 parent daf3a21 commit 9c88adc

File tree

14 files changed

+930
-768
lines changed

14 files changed

+930
-768
lines changed

src/impls.rs

Lines changed: 220 additions & 50 deletions
Large diffs are not rendered by default.

src/lib.rs

Lines changed: 47 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -805,6 +805,17 @@ pub unsafe trait KnownLayout {
805805
// resulting size would not fit in a `usize`.
806806
meta.size_for_metadata(Self::LAYOUT)
807807
}
808+
809+
#[doc(hidden)]
810+
#[must_use]
811+
#[inline(always)]
812+
fn cast_from_raw<P: KnownLayout<PointerMetadata = Self::PointerMetadata> + ?Sized>(
813+
ptr: NonNull<P>,
814+
) -> NonNull<Self> {
815+
let data = ptr.cast::<u8>();
816+
let meta = P::pointer_to_metadata(ptr.as_ptr());
817+
Self::raw_from_ptr_len(data, meta)
818+
}
808819
}
809820

810821
/// The metadata associated with a [`KnownLayout`] type.
@@ -2843,29 +2854,43 @@ unsafe fn try_read_from<S, T: TryFromBytes>(
28432854
// We use `from_mut` despite not mutating via `c_ptr` so that we don't need
28442855
// to add a `T: Immutable` bound.
28452856
let c_ptr = Ptr::from_mut(&mut candidate);
2846-
let c_ptr = c_ptr.transparent_wrapper_into_inner();
28472857
// SAFETY: `c_ptr` has no uninitialized sub-ranges because it derived from
28482858
// `candidate`, which the caller promises is entirely initialized. Since
28492859
// `candidate` is a `MaybeUninit`, it has no validity requirements, and so
2850-
// no values written to `c_ptr` can violate its validity. Since `c_ptr` has
2851-
// `Exclusive` aliasing, no mutations may happen except via `c_ptr` so long
2852-
// as it is live, so we don't need to worry about the fact that `c_ptr` may
2853-
// have more restricted validity than `candidate`.
2860+
// no values written to an `Initialized` `c_ptr` can violate its validity.
2861+
// Since `c_ptr` has `Exclusive` aliasing, no mutations may happen except
2862+
// via `c_ptr` so long as it is live, so we don't need to worry about the
2863+
// fact that `c_ptr` may have more restricted validity than `candidate`.
28542864
let c_ptr = unsafe { c_ptr.assume_validity::<invariant::Initialized>() };
2865+
let c_ptr = c_ptr.transmute();
28552866

2867+
// Since we don't have `T: KnownLayout`, we hack around that by using
2868+
// `Wrapping<T>`, which implements `KnownLayout` even if `T` doesn't.
2869+
//
28562870
// This call may panic. If that happens, it doesn't cause any soundness
2857-
// issues, as we have not generated any invalid state which we need to
2858-
// fix before returning.
2871+
// issues, as we have not generated any invalid state which we need to fix
2872+
// before returning.
28592873
//
2860-
// Note that one panic or post-monomorphization error condition is
2861-
// calling `try_into_valid` (and thus `is_bit_valid`) with a shared
2862-
// pointer when `Self: !Immutable`. Since `Self: Immutable`, this panic
2863-
// condition will not happen.
2864-
if !T::is_bit_valid(c_ptr.forget_aligned()) {
2874+
// Note that one panic or post-monomorphization error condition is calling
2875+
// `try_into_valid` (and thus `is_bit_valid`) with a shared pointer when
2876+
// `Self: !Immutable`. Since `Self: Immutable`, this panic condition will
2877+
// not happen.
2878+
if !Wrapping::<T>::is_bit_valid(c_ptr.forget_aligned()) {
28652879
return Err(ValidityError::new(source).into());
28662880
}
28672881

2868-
// SAFETY: We just validated that `candidate` contains a valid `T`.
2882+
fn _assert_same_size_and_validity<T>()
2883+
where
2884+
Wrapping<T>: pointer::TransmuteFrom<T, invariant::Valid, invariant::Valid>,
2885+
T: pointer::TransmuteFrom<Wrapping<T>, invariant::Valid, invariant::Valid>,
2886+
{
2887+
}
2888+
2889+
_assert_same_size_and_validity::<T>();
2890+
2891+
// SAFETY: We just validated that `candidate` contains a valid
2892+
// `Wrapping<T>`, which has the same size and bit validity as `T`, as
2893+
// guaranteed by the preceding type assertion.
28692894
Ok(unsafe { candidate.assume_init() })
28702895
}
28712896

@@ -3552,7 +3577,7 @@ pub unsafe trait FromBytes: FromZeros {
35523577
{
35533578
static_assert_dst_is_not_zst!(Self);
35543579
match Ptr::from_ref(source).try_cast_into_no_leftover::<_, BecauseImmutable>(None) {
3555-
Ok(ptr) => Ok(ptr.bikeshed_recall_valid().as_ref()),
3580+
Ok(ptr) => Ok(ptr.recall_validity().as_ref()),
35563581
Err(err) => Err(err.map_src(|src| src.as_ref())),
35573582
}
35583583
}
@@ -3788,7 +3813,7 @@ pub unsafe trait FromBytes: FromZeros {
37883813
{
37893814
static_assert_dst_is_not_zst!(Self);
37903815
match Ptr::from_mut(source).try_cast_into_no_leftover::<_, BecauseExclusive>(None) {
3791-
Ok(ptr) => Ok(ptr.bikeshed_recall_valid().as_mut()),
3816+
Ok(ptr) => Ok(ptr.recall_validity().as_mut()),
37923817
Err(err) => Err(err.map_src(|src| src.as_mut())),
37933818
}
37943819
}
@@ -4027,7 +4052,7 @@ pub unsafe trait FromBytes: FromZeros {
40274052
let source = Ptr::from_ref(source);
40284053
let maybe_slf = source.try_cast_into_no_leftover::<_, BecauseImmutable>(Some(count));
40294054
match maybe_slf {
4030-
Ok(slf) => Ok(slf.bikeshed_recall_valid().as_ref()),
4055+
Ok(slf) => Ok(slf.recall_validity().as_ref()),
40314056
Err(err) => Err(err.map_src(|s| s.as_ref())),
40324057
}
40334058
}
@@ -4258,7 +4283,9 @@ pub unsafe trait FromBytes: FromZeros {
42584283
let source = Ptr::from_mut(source);
42594284
let maybe_slf = source.try_cast_into_no_leftover::<_, BecauseImmutable>(Some(count));
42604285
match maybe_slf {
4261-
Ok(slf) => Ok(slf.bikeshed_recall_valid().as_mut()),
4286+
Ok(slf) => Ok(slf
4287+
.recall_validity::<_, (_, (_, (BecauseExclusive, BecauseExclusive)))>()
4288+
.as_mut()),
42624289
Err(err) => Err(err.map_src(|s| s.as_mut())),
42634290
}
42644291
}
@@ -4716,7 +4743,7 @@ fn ref_from_prefix_suffix<T: FromBytes + KnownLayout + Immutable + ?Sized>(
47164743
let (slf, prefix_suffix) = Ptr::from_ref(source)
47174744
.try_cast_into::<_, BecauseImmutable>(cast_type, meta)
47184745
.map_err(|err| err.map_src(|s| s.as_ref()))?;
4719-
Ok((slf.bikeshed_recall_valid().as_ref(), prefix_suffix.as_ref()))
4746+
Ok((slf.recall_validity().as_ref(), prefix_suffix.as_ref()))
47204747
}
47214748

47224749
/// Interprets the given affix of the given bytes as a `&mut Self` without
@@ -4728,15 +4755,15 @@ fn ref_from_prefix_suffix<T: FromBytes + KnownLayout + Immutable + ?Sized>(
47284755
/// If there are insufficient bytes, or if that affix of `source` is not
47294756
/// appropriately aligned, this returns `Err`.
47304757
#[inline(always)]
4731-
fn mut_from_prefix_suffix<T: FromBytes + KnownLayout + ?Sized>(
4758+
fn mut_from_prefix_suffix<T: FromBytes + IntoBytes + KnownLayout + ?Sized>(
47324759
source: &mut [u8],
47334760
meta: Option<T::PointerMetadata>,
47344761
cast_type: CastType,
47354762
) -> Result<(&mut T, &mut [u8]), CastError<&mut [u8], T>> {
47364763
let (slf, prefix_suffix) = Ptr::from_mut(source)
47374764
.try_cast_into::<_, BecauseExclusive>(cast_type, meta)
47384765
.map_err(|err| err.map_src(|s| s.as_mut()))?;
4739-
Ok((slf.bikeshed_recall_valid().as_mut(), prefix_suffix.as_mut()))
4766+
Ok((slf.recall_validity().as_mut(), prefix_suffix.as_mut()))
47404767
}
47414768

47424769
/// Analyzes whether a type is [`IntoBytes`].

src/pointer/invariant.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,8 @@ pub enum Initialized {}
178178
// required to uphold).
179179
unsafe impl Validity for Initialized {}
180180

181-
/// The referent of a `Ptr<T>` is bit-valid for `T`.
181+
/// The referent of a `Ptr<T>` is valid for `T`, upholding bit validity and any
182+
/// library safety invariants.
182183
pub enum Valid {}
183184
// SAFETY: `Valid`'s validity is well-defined for all `T: ?Sized`, and is not a
184185
// function of any property of `T` other than its bit validity.

src/pointer/mod.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,15 @@ mod inner;
1212
#[doc(hidden)]
1313
pub mod invariant;
1414
mod ptr;
15+
mod transmute;
1516

1617
#[doc(hidden)]
17-
pub use invariant::{BecauseExclusive, BecauseImmutable, Read};
18+
pub(crate) use transmute::*;
1819
#[doc(hidden)]
19-
pub use ptr::Ptr;
20+
pub use {
21+
invariant::{BecauseExclusive, BecauseImmutable, Read},
22+
ptr::Ptr,
23+
};
2024

2125
use crate::Unaligned;
2226

0 commit comments

Comments
 (0)