Skip to content

Commit feb1f37

Browse files
committed
[WIP] Break TransmuteFrom into Shrink vs Overwrite
Also, only implement TryTransmuteFromPtr once in terms of MutationCompatible. gherrit-pr-id: I1e15473bf871e5b53a6c093e6a79f48e6498aa04
1 parent 20f0bc3 commit feb1f37

File tree

9 files changed

+241
-140
lines changed

9 files changed

+241
-140
lines changed

src/impls.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,8 @@ assert_unaligned!(bool);
105105
// pattern 0x01.
106106
const _: () = unsafe {
107107
unsafe_impl!(=> TryFromBytes for bool; |byte| {
108-
let byte = byte.transmute::<u8, invariant::Valid, _>();
108+
let mut byte = byte;
109+
let byte = byte.reborrow().into_shared().transmute::<u8, invariant::Valid, _>();
109110
*byte.unaligned_as_ref() < 2
110111
})
111112
};
@@ -135,7 +136,8 @@ const _: () = unsafe { unsafe_impl!(char: Immutable, FromZeros, IntoBytes) };
135136
// `char`.
136137
const _: () = unsafe {
137138
unsafe_impl!(=> TryFromBytes for char; |c| {
138-
let c = c.transmute::<Unalign<u32>, invariant::Valid, _>();
139+
let mut c = c;
140+
let c = c.reborrow().into_shared().transmute::<Unalign<u32>, invariant::Valid, _>();
139141
let c = c.read_unaligned().into_inner();
140142
char::from_u32(c).is_some()
141143
});
@@ -168,7 +170,8 @@ const _: () = unsafe { unsafe_impl!(str: Immutable, FromZeros, IntoBytes, Unalig
168170
// Returns `Err` if the slice is not UTF-8.
169171
const _: () = unsafe {
170172
unsafe_impl!(=> TryFromBytes for str; |c| {
171-
let c = c.transmute::<[u8], invariant::Valid, _>();
173+
let mut c = c;
174+
let c = c.reborrow().into_shared().transmute::<[u8], invariant::Valid, _>();
172175
let c = c.unaligned_as_ref();
173176
core::str::from_utf8(c).is_ok()
174177
})
@@ -181,7 +184,8 @@ macro_rules! unsafe_impl_try_from_bytes_for_nonzero {
181184
$(
182185
unsafe_impl!(=> TryFromBytes for $nonzero; |n| {
183186
impl_size_compat!($nonzero, Unalign<$prim>);
184-
let n = n.transmute::<Unalign<$prim>, invariant::Valid, _>();
187+
let mut n = n;
188+
let n = n.reborrow().into_shared().transmute::<Unalign<$prim>, invariant::Valid, _>();
185189
$nonzero::new(n.read_unaligned().into_inner()).is_some()
186190
});
187191
)*

src/lib.rs

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,7 @@ use core::{
384384
#[cfg(feature = "std")]
385385
use std::io;
386386

387-
use crate::pointer::invariant::{self, BecauseExclusive};
387+
use crate::pointer::{invariant, BecauseBidirectional};
388388

389389
#[cfg(any(feature = "alloc", test, kani))]
390390
extern crate alloc;
@@ -1843,7 +1843,7 @@ pub unsafe trait TryFromBytes {
18431843
Self: KnownLayout + IntoBytes,
18441844
{
18451845
static_assert_dst_is_not_zst!(Self);
1846-
match Ptr::from_mut(bytes).try_cast_into_no_leftover::<Self, BecauseExclusive>(None) {
1846+
match Ptr::from_mut(bytes).try_cast_into_no_leftover(None) {
18471847
Ok(source) => {
18481848
// This call may panic. If that happens, it doesn't cause any soundness
18491849
// issues, as we have not generated any invalid state which we need to
@@ -1855,9 +1855,7 @@ pub unsafe trait TryFromBytes {
18551855
// condition will not happen.
18561856
match source.try_into_valid() {
18571857
Ok(source) => Ok(source.as_mut()),
1858-
Err(e) => {
1859-
Err(e.map_src(|src| src.as_bytes::<BecauseExclusive>().as_mut()).into())
1860-
}
1858+
Err(e) => Err(e.map_src(|src| src.as_bytes().as_mut()).into()),
18611859
}
18621860
}
18631861
Err(e) => Err(e.map_src(Ptr::as_mut).into()),
@@ -2424,8 +2422,7 @@ pub unsafe trait TryFromBytes {
24242422
where
24252423
Self: KnownLayout<PointerMetadata = usize> + IntoBytes,
24262424
{
2427-
match Ptr::from_mut(source).try_cast_into_no_leftover::<Self, BecauseExclusive>(Some(count))
2428-
{
2425+
match Ptr::from_mut(source).try_cast_into_no_leftover(Some(count)) {
24292426
Ok(source) => {
24302427
// This call may panic. If that happens, it doesn't cause any soundness
24312428
// issues, as we have not generated any invalid state which we need to
@@ -2437,9 +2434,7 @@ pub unsafe trait TryFromBytes {
24372434
// condition will not happen.
24382435
match source.try_into_valid() {
24392436
Ok(source) => Ok(source.as_mut()),
2440-
Err(e) => {
2441-
Err(e.map_src(|src| src.as_bytes::<BecauseExclusive>().as_mut()).into())
2442-
}
2437+
Err(e) => Err(e.map_src(|src| src.as_bytes().as_mut()).into()),
24432438
}
24442439
}
24452440
Err(e) => Err(e.map_src(Ptr::as_mut).into()),
@@ -2847,7 +2842,7 @@ fn try_mut_from_prefix_suffix<T: IntoBytes + TryFromBytes + KnownLayout + ?Sized
28472842
cast_type: CastType,
28482843
meta: Option<T::PointerMetadata>,
28492844
) -> Result<(&mut T, &mut [u8]), TryCastError<&mut [u8], T>> {
2850-
match Ptr::from_mut(candidate).try_cast_into::<T, BecauseExclusive>(cast_type, meta) {
2845+
match Ptr::from_mut(candidate).try_cast_into(cast_type, meta) {
28512846
Ok((candidate, prefix_suffix)) => {
28522847
// This call may panic. If that happens, it doesn't cause any soundness
28532848
// issues, as we have not generated any invalid state which we need to
@@ -2859,7 +2854,7 @@ fn try_mut_from_prefix_suffix<T: IntoBytes + TryFromBytes + KnownLayout + ?Sized
28592854
// condition will not happen.
28602855
match candidate.try_into_valid() {
28612856
Ok(valid) => Ok((valid.as_mut(), prefix_suffix.as_mut())),
2862-
Err(e) => Err(e.map_src(|src| src.as_bytes::<BecauseExclusive>().as_mut()).into()),
2857+
Err(e) => Err(e.map_src(|src| src.as_bytes().as_mut()).into()),
28632858
}
28642859
}
28652860
Err(e) => Err(e.map_src(Ptr::as_mut).into()),
@@ -3838,8 +3833,8 @@ pub unsafe trait FromBytes: FromZeros {
38383833
Self: IntoBytes + KnownLayout,
38393834
{
38403835
static_assert_dst_is_not_zst!(Self);
3841-
match Ptr::from_mut(source).try_cast_into_no_leftover::<_, BecauseExclusive>(None) {
3842-
Ok(ptr) => Ok(ptr.recall_validity::<_, (_, (_, _))>().as_mut()),
3836+
match Ptr::from_mut(source).try_cast_into_no_leftover(None) {
3837+
Ok(ptr) => Ok(ptr.recall_validity::<_, BecauseBidirectional>().as_mut()),
38433838
Err(err) => Err(err.map_src(|src| src.as_mut())),
38443839
}
38453840
}
@@ -4307,11 +4302,9 @@ pub unsafe trait FromBytes: FromZeros {
43074302
Self: IntoBytes + KnownLayout<PointerMetadata = usize> + Immutable,
43084303
{
43094304
let source = Ptr::from_mut(source);
4310-
let maybe_slf = source.try_cast_into_no_leftover::<_, BecauseImmutable>(Some(count));
4305+
let maybe_slf = source.try_cast_into_no_leftover(Some(count));
43114306
match maybe_slf {
4312-
Ok(slf) => Ok(slf
4313-
.recall_validity::<_, (_, (_, (BecauseExclusive, BecauseExclusive)))>()
4314-
.as_mut()),
4307+
Ok(slf) => Ok(slf.recall_validity::<_, BecauseBidirectional>().as_mut()),
43154308
Err(err) => Err(err.map_src(|s| s.as_mut())),
43164309
}
43174310
}
@@ -4668,7 +4661,7 @@ pub unsafe trait FromBytes: FromZeros {
46684661
// cannot be violated even though `buf` may have more permissive bit
46694662
// validity than `ptr`.
46704663
let ptr = unsafe { ptr.assume_validity::<invariant::Initialized>() };
4671-
let ptr = ptr.as_bytes::<BecauseExclusive>();
4664+
let ptr = ptr.as_bytes();
46724665
src.read_exact(ptr.as_mut())?;
46734666
// SAFETY: `buf` entirely consists of initialized bytes, and `Self` is
46744667
// `FromBytes`.
@@ -4787,9 +4780,9 @@ fn mut_from_prefix_suffix<T: FromBytes + IntoBytes + KnownLayout + ?Sized>(
47874780
cast_type: CastType,
47884781
) -> Result<(&mut T, &mut [u8]), CastError<&mut [u8], T>> {
47894782
let (slf, prefix_suffix) = Ptr::from_mut(source)
4790-
.try_cast_into::<_, BecauseExclusive>(cast_type, meta)
4783+
.try_cast_into(cast_type, meta)
47914784
.map_err(|err| err.map_src(|s| s.as_mut()))?;
4792-
Ok((slf.recall_validity::<_, (_, (_, _))>().as_mut(), prefix_suffix.as_mut()))
4785+
Ok((slf.recall_validity::<_, BecauseBidirectional>().as_mut(), prefix_suffix.as_mut()))
47934786
}
47944787

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

src/pointer/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ mod transmute;
1818
pub use {inner::PtrInner, transmute::*};
1919
#[doc(hidden)]
2020
pub use {
21-
invariant::{BecauseExclusive, BecauseImmutable, Read},
21+
invariant::{BecauseExclusive, Read},
2222
ptr::Ptr,
2323
};
2424

@@ -30,11 +30,11 @@ pub type Maybe<'a, T, Aliasing = invariant::Shared, Alignment = invariant::Unali
3030
Ptr<'a, T, (Aliasing, Alignment, invariant::Initialized)>;
3131

3232
/// Checks if the referent is zeroed.
33-
pub(crate) fn is_zeroed<T, I>(ptr: Ptr<'_, T, I>) -> bool
33+
pub(crate) fn is_zeroed<T, I>(mut ptr: Ptr<'_, T, I>) -> bool
3434
where
3535
T: crate::Immutable + crate::KnownLayout,
3636
I: invariant::Invariants<Validity = invariant::Initialized>,
3737
I::Aliasing: invariant::Reference,
3838
{
39-
ptr.as_bytes::<BecauseImmutable>().as_ref().iter().all(|&byte| byte == 0)
39+
ptr.reborrow().into_shared().as_bytes().as_ref().iter().all(|&byte| byte == 0)
4040
}

src/pointer/ptr.rs

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -269,9 +269,8 @@ mod _conversions {
269269
{
270270
/// Reborrows `self`, producing another `Ptr`.
271271
///
272-
/// Since `self` is borrowed immutably, this prevents any mutable
273-
/// methods from being called on `self` as long as the returned `Ptr`
274-
/// exists.
272+
/// Since `self` is borrowed mutably, this prevents `self` from being
273+
/// used as long as the returned `Ptr` exists.
275274
#[doc(hidden)]
276275
#[inline]
277276
#[allow(clippy::needless_lifetimes)] // Allows us to name the lifetime in the safety comment below.
@@ -312,6 +311,23 @@ mod _conversions {
312311
// memory may be live.
313312
unsafe { Ptr::from_inner(self.as_inner()) }
314313
}
314+
315+
/// Converts `self` to a shared `Ptr`.
316+
#[doc(hidden)]
317+
#[inline]
318+
#[allow(clippy::needless_lifetimes)] // Allows us to name the lifetime in the safety comment below.
319+
pub fn into_shared(self) -> Ptr<'a, T, (Shared, I::Alignment, I::Validity)> {
320+
// SAFETY: Since `I::Aliasing: Reference`, there are two cases for
321+
// `I::Aliasing`:
322+
// - For `invariant::Shared`, the returned `Ptr` is identical, so no
323+
// new proof obligations are introduced.
324+
// - For `invariant::Exclusive`: Since `self` has `Exclusive`
325+
// aliasing, it is guaranteed that no other `Ptr`s or references
326+
// permit concurrent access to the referent. Thus, the returned
327+
// `Ptr` is the only reference to the referent which may read or
328+
// write the referent during `'a`.
329+
unsafe { self.assume_aliasing() }
330+
}
315331
}
316332

317333
/// `Ptr<'a, T>` → `&'a mut T`
@@ -920,8 +936,10 @@ mod _casts {
920936
cast: F,
921937
) -> Ptr<'a, U, (I::Aliasing, Unaligned, I::Validity)>
922938
where
923-
T: MutationCompatible<U, I::Aliasing, I::Validity, I::Validity, R>,
924-
U: 'a + ?Sized + CastableFrom<T, I::Validity, I::Validity>,
939+
U: 'a
940+
+ MutationCompatible<T, I::Aliasing, I::Validity, I::Validity, R>
941+
+ CastableFrom<T, I::Validity, I::Validity>
942+
+ ?Sized,
925943
F: FnOnce(PtrInner<'_, T>) -> PtrInner<'_, U>,
926944
{
927945
// SAFETY: Because `T: MutationCompatible<U, I::Aliasing, R>`, one
@@ -947,7 +965,7 @@ mod _casts {
947965
#[allow(clippy::wrong_self_convention)]
948966
pub(crate) fn as_bytes<R>(self) -> Ptr<'a, [u8], (I::Aliasing, Aligned, Valid)>
949967
where
950-
T: Read<I::Aliasing, R>,
968+
[u8]: MutationCompatible<T, I::Aliasing, I::Validity, I::Validity, R>,
951969
I::Aliasing: Reference,
952970
{
953971
let bytes = match T::size_of_val_raw(self.as_inner().as_non_null()) {
@@ -981,7 +999,7 @@ mod _casts {
981999
};
9821000

9831001
let ptr = ptr.bikeshed_recall_aligned();
984-
ptr.recall_validity::<_, (_, (_, _))>()
1002+
ptr.recall_validity::<Valid, _>()
9851003
}
9861004
}
9871005

@@ -1066,7 +1084,8 @@ mod _casts {
10661084
>
10671085
where
10681086
I::Aliasing: Reference,
1069-
U: 'a + ?Sized + KnownLayout + Read<I::Aliasing, R>,
1087+
U: 'a + ?Sized + KnownLayout,
1088+
[u8]: MutationCompatible<U, I::Aliasing, Initialized, Initialized, R>,
10701089
{
10711090
let (inner, remainder) =
10721091
self.as_inner().try_cast_into(cast_type, meta).map_err(|err| {
@@ -1129,7 +1148,8 @@ mod _casts {
11291148
) -> Result<Ptr<'a, U, (I::Aliasing, Aligned, Initialized)>, CastError<Self, U>>
11301149
where
11311150
I::Aliasing: Reference,
1132-
U: 'a + ?Sized + KnownLayout + Read<I::Aliasing, R>,
1151+
U: 'a + ?Sized + KnownLayout,
1152+
[u8]: MutationCompatible<U, I::Aliasing, Initialized, Initialized, R>,
11331153
{
11341154
// FIXME(#67): Remove this allow. See NonNulSlicelExt for more
11351155
// details.
@@ -1261,7 +1281,7 @@ mod tests {
12611281
use super::*;
12621282
#[allow(unused)] // Needed on our MSRV, but considered unused on later toolchains.
12631283
use crate::util::AsAddress;
1264-
use crate::{pointer::BecauseImmutable, util::testutil::AU64, FromBytes, Immutable};
1284+
use crate::{pointer::invariant::BecauseImmutable, util::testutil::AU64, FromBytes, Immutable};
12651285

12661286
mod test_ptr_try_cast_into_soundness {
12671287
use super::*;

0 commit comments

Comments
 (0)