Skip to content

Commit 3e52166

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

File tree

11 files changed

+349
-81
lines changed

11 files changed

+349
-81
lines changed

src/impls.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,8 @@ mod atomics {
439439

440440
impl_known_layout!(AtomicBool);
441441

442-
impl_for_transparent_wrapper!(=> TryFromBytes for AtomicBool);
442+
// impl_for_transparent_wrapper!(=> TryFromBytes for AtomicBool);
443+
impl_for_transmute_from!(=> TryFromBytes for AtomicBool [UnsafeCell<bool>]);
443444
impl_for_transparent_wrapper!(=> FromZeros for AtomicBool);
444445
impl_for_transparent_wrapper!(=> IntoBytes for AtomicBool);
445446

@@ -472,6 +473,7 @@ mod atomics {
472473
/// All of these pass an atomic type and that type's native equivalent, as
473474
/// required by the macro safety preconditions.
474475
unsafe_impl_transparent_wrapper_for_atomic!(AtomicU8 [u8], AtomicI8 [i8], AtomicBool [bool]);
476+
unsafe_impl_transmute_from_for_atomic!(AtomicU8 [u8], AtomicI8 [i8], AtomicBool [bool]);
475477
}
476478
}
477479

@@ -489,6 +491,7 @@ mod atomics {
489491
/// All of these pass an atomic type and that type's native equivalent, as
490492
/// required by the macro safety preconditions.
491493
unsafe_impl_transparent_wrapper_for_atomic!(AtomicU16 [u16], AtomicI16 [i16]);
494+
unsafe_impl_transmute_from_for_atomic!(AtomicU16 [u16], AtomicI16 [i16]);
492495
}
493496
}
494497

@@ -506,6 +509,7 @@ mod atomics {
506509
/// All of these pass an atomic type and that type's native equivalent, as
507510
/// required by the macro safety preconditions.
508511
unsafe_impl_transparent_wrapper_for_atomic!(AtomicU32 [u32], AtomicI32 [i32]);
512+
unsafe_impl_transmute_from_for_atomic!(AtomicU32 [u32], AtomicI32 [i32]);
509513
}
510514
}
511515

@@ -523,6 +527,7 @@ mod atomics {
523527
/// All of these pass an atomic type and that type's native equivalent, as
524528
/// required by the macro safety preconditions.
525529
unsafe_impl_transparent_wrapper_for_atomic!(AtomicU64 [u64], AtomicI64 [i64]);
530+
unsafe_impl_transmute_from_for_atomic!(AtomicU64 [u64], AtomicI64 [i64]);
526531
}
527532
}
528533

@@ -548,6 +553,9 @@ mod atomics {
548553
/// required by the macro safety preconditions.
549554
unsafe_impl_transparent_wrapper_for_atomic!(AtomicUsize [usize], AtomicIsize [isize]);
550555
unsafe_impl_transparent_wrapper_for_atomic!(T => AtomicPtr<T> [*mut T]);
556+
557+
unsafe_impl_transmute_from_for_atomic!(AtomicUsize [usize], AtomicIsize [isize]);
558+
unsafe_impl_transmute_from_for_atomic!(T => AtomicPtr<T> [*mut T]);
551559
}
552560
}
553561
}

src/lib.rs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,10 @@ use core::{
375375
#[cfg(feature = "std")]
376376
use std::io;
377377

378-
use crate::pointer::invariant::{self, BecauseExclusive};
378+
use crate::pointer::{
379+
invariant::{self, BecauseExclusive},
380+
BecauseRead,
381+
};
379382

380383
#[cfg(any(feature = "alloc", test))]
381384
extern crate alloc;
@@ -805,6 +808,14 @@ pub unsafe trait KnownLayout {
805808
// resulting size would not fit in a `usize`.
806809
meta.size_for_metadata(Self::LAYOUT)
807810
}
811+
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,7 +2854,7 @@ 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();
2857+
let c_ptr = c_ptr.transmute();
28472858
// SAFETY: `c_ptr` has no uninitialized sub-ranges because it derived from
28482859
// `candidate`, which the caller promises is entirely initialized. Since
28492860
// `candidate` is a `MaybeUninit`, it has no validity requirements, and so
@@ -2861,7 +2872,7 @@ unsafe fn try_read_from<S, T: TryFromBytes>(
28612872
// calling `try_into_valid` (and thus `is_bit_valid`) with a shared
28622873
// pointer when `Self: !Immutable`. Since `Self: Immutable`, this panic
28632874
// condition will not happen.
2864-
if !T::is_bit_valid(c_ptr.forget_aligned()) {
2875+
if !util::SizedKnownLayout::<T>::is_bit_valid(c_ptr.forget_aligned()) {
28652876
return Err(ValidityError::new(source).into());
28662877
}
28672878

@@ -4258,7 +4269,7 @@ pub unsafe trait FromBytes: FromZeros {
42584269
let source = Ptr::from_mut(source);
42594270
let maybe_slf = source.try_cast_into_no_leftover::<_, BecauseImmutable>(Some(count));
42604271
match maybe_slf {
4261-
Ok(slf) => Ok(slf.bikeshed_recall_valid().as_mut()),
4272+
Ok(slf) => Ok(slf.bikeshed_recall_valid::<(BecauseRead, BecauseExclusive)>().as_mut()),
42624273
Err(err) => Err(err.map_src(|s| s.as_mut())),
42634274
}
42644275
}
@@ -4728,7 +4739,7 @@ fn ref_from_prefix_suffix<T: FromBytes + KnownLayout + Immutable + ?Sized>(
47284739
/// If there are insufficient bytes, or if that affix of `source` is not
47294740
/// appropriately aligned, this returns `Err`.
47304741
#[inline(always)]
4731-
fn mut_from_prefix_suffix<T: FromBytes + KnownLayout + ?Sized>(
4742+
fn mut_from_prefix_suffix<T: FromBytes + IntoBytes + KnownLayout + ?Sized>(
47324743
source: &mut [u8],
47334744
meta: Option<T::PointerMetadata>,
47344745
cast_type: CastType,

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

src/pointer/ptr.rs

Lines changed: 40 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ use core::{
1212
ptr::NonNull,
1313
};
1414

15-
use super::{inner::PtrInner, invariant::*};
1615
use crate::{
16+
pointer::{inner::PtrInner, invariant::*, transmute::TransmuteFromPtr},
1717
util::{AlignmentVariance, Covariant, TransparentWrapper, ValidityVariance},
1818
AlignmentError, CastError, CastType, KnownLayout, SizeError, TryFromBytes, ValidityError,
1919
};
@@ -391,7 +391,7 @@ mod _conversions {
391391
{
392392
/// Converts `self` to a transparent wrapper type into a `Ptr` to the
393393
/// wrapped inner type.
394-
pub(crate) fn transparent_wrapper_into_inner(
394+
fn transparent_wrapper_into_inner(
395395
self,
396396
) -> Ptr<
397397
'a,
@@ -430,6 +430,17 @@ mod _conversions {
430430
where
431431
I: Invariants,
432432
{
433+
pub fn transmute<U, V, R>(self) -> Ptr<'a, U, (I::Aliasing, Unaligned, V)>
434+
where
435+
T: KnownLayout,
436+
V: Validity,
437+
U: TransmuteFromPtr<T, I::Aliasing, I::Validity, V, R>
438+
+ KnownLayout<PointerMetadata = T::PointerMetadata>
439+
+ ?Sized,
440+
{
441+
self.transmute_unchecked(|t: NonNull<T>| U::cast_from_raw(t))
442+
}
443+
433444
/// Casts to a different (unsized) target type without checking interior
434445
/// mutability.
435446
///
@@ -460,14 +471,14 @@ mod _conversions {
460471
) -> Ptr<'a, U, (I::Aliasing, Unaligned, V)>
461472
where
462473
V: Validity,
463-
F: FnOnce(*mut T) -> *mut U,
474+
F: FnOnce(NonNull<T>) -> NonNull<U>,
464475
{
465-
let ptr = cast(self.as_inner().as_non_null().as_ptr());
476+
let ptr = cast(self.as_inner().as_non_null());
466477

467-
// SAFETY: Caller promises that `cast` returns a pointer whose
468-
// address is in the range of `self.as_inner().as_non_null()`'s referent. By
469-
// invariant, none of these addresses are null.
470-
let ptr = unsafe { NonNull::new_unchecked(ptr) };
478+
// // SAFETY: Caller promises that `cast` returns a pointer whose
479+
// // address is in the range of `self.as_inner().as_non_null()`'s referent. By
480+
// // invariant, none of these addresses are null.
481+
// let ptr = unsafe { NonNull::new_unchecked(ptr) };
471482

472483
// SAFETY:
473484
//
@@ -552,7 +563,7 @@ mod _conversions {
552563
// validity of the other.
553564
let ptr = unsafe {
554565
#[allow(clippy::as_conversions)]
555-
self.transmute_unchecked(|p: *mut T| p as *mut crate::Unalign<T>)
566+
self.transmute_unchecked(NonNull::cast::<crate::Unalign<T>>)
556567
};
557568
ptr.bikeshed_recall_aligned()
558569
}
@@ -561,6 +572,8 @@ mod _conversions {
561572

562573
/// State transitions between invariants.
563574
mod _transitions {
575+
use crate::pointer::transmute::TryTransmuteFromPtr;
576+
564577
use super::*;
565578

566579
impl<'a, T, I> Ptr<'a, T, I>
@@ -819,14 +832,11 @@ mod _transitions {
819832
#[inline]
820833
// TODO(#859): Reconsider the name of this method before making it
821834
// public.
822-
pub fn bikeshed_recall_valid(self) -> Ptr<'a, T, (I::Aliasing, I::Alignment, Valid)>
835+
pub fn bikeshed_recall_valid<R>(self) -> Ptr<'a, T, (I::Aliasing, I::Alignment, Valid)>
823836
where
824-
T: crate::FromBytes,
837+
T: crate::FromBytes + TryTransmuteFromPtr<T, I::Aliasing, I::Validity, Valid, R>,
825838
I: Invariants<Validity = Initialized>,
826839
{
827-
// TODO(#1866): Fix this unsoundness.
828-
829-
// SAFETY: This is unsound!
830840
unsafe { self.assume_valid() }
831841
}
832842

@@ -843,24 +853,24 @@ mod _transitions {
843853
/// On error, unsafe code may rely on this method's returned
844854
/// `ValidityError` containing `self`.
845855
#[inline]
846-
pub(crate) fn try_into_valid<R>(
856+
pub(crate) fn try_into_valid<R, S>(
847857
mut self,
848858
) -> Result<Ptr<'a, T, (I::Aliasing, I::Alignment, Valid)>, ValidityError<Self, T>>
849859
where
850-
T: TryFromBytes + Read<I::Aliasing, R>,
860+
T: TryFromBytes
861+
+ Read<I::Aliasing, R>
862+
+ TryTransmuteFromPtr<T, I::Aliasing, I::Validity, Valid, S>,
851863
I::Aliasing: Reference,
852864
I: Invariants<Validity = Initialized>,
853865
{
854866
// This call may panic. If that happens, it doesn't cause any soundness
855867
// issues, as we have not generated any invalid state which we need to
856868
// fix before returning.
857869
if T::is_bit_valid(self.reborrow().forget_aligned()) {
858-
// SAFETY: If `T::is_bit_valid`, code may assume that `self`
859-
// contains a bit-valid instance of `Self`.
870+
// TODO: Complete this safety comment.
860871
//
861-
// TODO(#1866): This is unsound! The returned `Ptr` may permit
862-
// writing referents which do not satisfy the `Initialized`
863-
// validity invariant of `self`.
872+
// If `T::is_bit_valid`, code may assume that `self` contains a
873+
// bit-valid instance of `Self`.
864874
Ok(unsafe { self.assume_valid() })
865875
} else {
866876
Err(ValidityError::new(self))
@@ -904,7 +914,7 @@ mod _casts {
904914
/// at ranges identical to those at which `UnsafeCell`s exist in `*p`
905915
#[doc(hidden)]
906916
#[inline]
907-
pub unsafe fn cast_unsized_unchecked<U, F: FnOnce(*mut T) -> *mut U>(
917+
pub unsafe fn cast_unsized_unchecked<U, F: FnOnce(NonNull<T>) -> NonNull<U>>(
908918
self,
909919
cast: F,
910920
) -> Ptr<'a, U, (I::Aliasing, Unaligned, I::Validity)>
@@ -947,7 +957,7 @@ mod _casts {
947957
where
948958
T: Read<I::Aliasing, R>,
949959
U: 'a + ?Sized + Read<I::Aliasing, S> + CastableFrom<T, I::Validity, I::Validity>,
950-
F: FnOnce(*mut T) -> *mut U,
960+
F: FnOnce(NonNull<T>) -> NonNull<U>,
951961
{
952962
// SAFETY: Because `T` and `U` both implement `Read<I::Aliasing, _>`,
953963
// either:
@@ -988,9 +998,8 @@ mod _casts {
988998
// returned pointer addresses the same bytes as `p`
989999
// - `slice_from_raw_parts_mut` and `.cast` both preserve provenance
9901000
let ptr: Ptr<'a, [u8], _> = unsafe {
991-
self.cast_unsized(|p: *mut T| {
992-
#[allow(clippy::as_conversions)]
993-
core::ptr::slice_from_raw_parts_mut(p.cast::<u8>(), bytes)
1001+
self.cast_unsized(|p: NonNull<T>| {
1002+
core::ptr::NonNull::slice_from_raw_parts(p.cast::<u8>(), bytes)
9941003
})
9951004
};
9961005

@@ -1214,7 +1223,7 @@ mod _casts {
12141223
// inner type `T`. A consequence of this guarantee is that it is
12151224
// possible to convert between `T` and `UnsafeCell<T>`.
12161225
#[allow(clippy::as_conversions)]
1217-
let ptr = unsafe { self.transmute_unchecked(|p| p as *mut T) };
1226+
let ptr = unsafe { self.transmute_unchecked(|p| cast!(p => NonNull<T>)) };
12181227

12191228
// SAFETY: `UnsafeCell<T>` has the same alignment as `T` [1],
12201229
// and so if `self` is guaranteed to be aligned, then so is the
@@ -1321,10 +1330,12 @@ mod tests {
13211330
};
13221331

13231332
// SAFETY: The bytes in `slf` must be initialized.
1324-
unsafe fn validate_and_get_len<T: ?Sized + KnownLayout + FromBytes>(
1333+
unsafe fn validate_and_get_len<
1334+
T: ?Sized + KnownLayout + FromBytes + Immutable,
1335+
>(
13251336
slf: Ptr<'_, T, (Shared, Aligned, Initialized)>,
13261337
) -> usize {
1327-
let t = slf.bikeshed_recall_valid().as_ref();
1338+
let t = slf.bikeshed_recall_valid::<BecauseImmutable>().as_ref();
13281339

13291340
let bytes = {
13301341
let len = mem::size_of_val(t);

0 commit comments

Comments
 (0)