Skip to content

Commit c43bbed

Browse files
joshlfjswrenn
andauthored
Add Src: FromBytes in try_transmute_mut!, Self: IntoBytes to TryFromBytes::try_mut* (#2343)
* Enforce `Src: FromBytes` in `try_transmute_mut!` (#2229) Ensures that the source reference remains valid after the transmuted (and possibly mutated) destination is dropped. Makes progress on #2226 gherrit-pr-id: I425e7d5103cb3b2a9e7107bf9df0743dca2e08cb * Add `Self: IntoBytes` bound to `TryFromBytes::try_mut*` Consider that `MaybeUninit<u8>` is `TryFromBytes`. If a `&mut [u8]` is cast into a `&mut MaybeUninit<u8>`, then uninit bytes are written, the shadowed `&mut [u8]`'s referent will no longer be valid. Makes progress towards #2226 and #1866. gherrit-pr-id: Ib233c4d0643e0690c53a37a08d9845e5fe43249c --------- Co-authored-by: Jack Wrenn <[email protected]> Co-authored-by: Jack Wrenn <[email protected]>
1 parent 17e7e4d commit c43bbed

17 files changed

+806
-116
lines changed

src/impls.rs

+46-4
Original file line numberDiff line numberDiff line change
@@ -1164,6 +1164,24 @@ mod tests {
11641164
}
11651165
}
11661166

1167+
pub(super) trait TestTryFromMut<T: ?Sized> {
1168+
#[allow(clippy::needless_lifetimes)]
1169+
fn test_try_from_mut<'bytes>(
1170+
&self,
1171+
bytes: &'bytes mut [u8],
1172+
) -> Option<Option<&'bytes mut T>>;
1173+
}
1174+
1175+
impl<T: TryFromBytes + IntoBytes + KnownLayout + ?Sized> TestTryFromMut<T> for AutorefWrapper<T> {
1176+
#[allow(clippy::needless_lifetimes)]
1177+
fn test_try_from_mut<'bytes>(
1178+
&self,
1179+
bytes: &'bytes mut [u8],
1180+
) -> Option<Option<&'bytes mut T>> {
1181+
Some(T::try_mut_from_bytes(bytes).ok())
1182+
}
1183+
}
1184+
11671185
pub(super) trait TestTryReadFrom<T> {
11681186
fn test_try_read_from(&self, bytes: &[u8]) -> Option<Option<T>>;
11691187
}
@@ -1255,6 +1273,25 @@ mod tests {
12551273
None
12561274
}
12571275

1276+
#[allow(clippy::needless_lifetimes)]
1277+
fn test_try_from_mut<'bytes>(&mut self, _bytes: &'bytes mut [u8]) -> Option<Option<&'bytes mut $ty>> {
1278+
assert_on_allowlist!(
1279+
test_try_from_mut($ty):
1280+
Option<Box<UnsafeCell<NotZerocopy>>>,
1281+
Option<&'static UnsafeCell<NotZerocopy>>,
1282+
Option<&'static mut UnsafeCell<NotZerocopy>>,
1283+
Option<NonNull<UnsafeCell<NotZerocopy>>>,
1284+
Option<fn()>,
1285+
Option<FnManyArgs>,
1286+
Option<extern "C" fn()>,
1287+
Option<ECFnManyArgs>,
1288+
*const NotZerocopy,
1289+
*mut NotZerocopy
1290+
);
1291+
1292+
None
1293+
}
1294+
12581295
fn test_try_read_from(&mut self, _bytes: &[u8]) -> Option<Option<&$ty>> {
12591296
assert_on_allowlist!(
12601297
test_try_read_from($ty):
@@ -1363,8 +1400,10 @@ mod tests {
13631400
let bytes_mut = &mut vec.as_mut_slice()[offset..offset+size];
13641401
bytes_mut.copy_from_slice(bytes);
13651402

1366-
let res = <$ty as TryFromBytes>::try_mut_from_bytes(bytes_mut);
1367-
assert!(res.is_ok(), "{}::try_mut_from_bytes({:?}): got `Err`, expected `Ok`", stringify!($ty), val);
1403+
let res = ww.test_try_from_mut(bytes_mut);
1404+
if let Some(res) = res {
1405+
assert!(res.is_some(), "{}::try_mut_from_bytes({:?}): got `None`, expected `Some`", stringify!($ty), val);
1406+
}
13681407
}
13691408

13701409
let res = bytes.and_then(|bytes| ww.test_try_read_from(bytes));
@@ -1384,8 +1423,11 @@ mod tests {
13841423
assert!(res.is_none(), "{}::try_ref_from_bytes({:?}): got Some, expected None", stringify!($ty), c);
13851424
}
13861425

1387-
let res = <$ty as TryFromBytes>::try_mut_from_bytes(c);
1388-
assert!(res.is_err(), "{}::try_mut_from_bytes({:?}): got Ok, expected Err", stringify!($ty), c);
1426+
let res = w.test_try_from_mut(c);
1427+
if let Some(res) = res {
1428+
assert!(res.is_none(), "{}::try_mut_from_bytes({:?}): got Some, expected None", stringify!($ty), c);
1429+
}
1430+
13891431

13901432
let res = w.test_try_read_from(c);
13911433
if let Some(res) = res {

src/lib.rs

+43-43
Original file line numberDiff line numberDiff line change
@@ -1713,8 +1713,8 @@ pub unsafe trait TryFromBytes {
17131713
/// use zerocopy::*;
17141714
/// # use zerocopy_derive::*;
17151715
///
1716-
/// #[derive(TryFromBytes, KnownLayout)]
1717-
/// #[repr(C)]
1716+
/// #[derive(TryFromBytes, IntoBytes, KnownLayout)]
1717+
/// #[repr(C, packed)]
17181718
/// struct ZSTy {
17191719
/// leading_sized: [u8; 2],
17201720
/// trailing_dst: [()],
@@ -1731,17 +1731,17 @@ pub unsafe trait TryFromBytes {
17311731
/// # use zerocopy_derive::*;
17321732
///
17331733
/// // The only valid value of this type is the byte `0xC0`
1734-
/// #[derive(TryFromBytes, KnownLayout)]
1734+
/// #[derive(TryFromBytes, IntoBytes, KnownLayout)]
17351735
/// #[repr(u8)]
17361736
/// enum C0 { xC0 = 0xC0 }
17371737
///
17381738
/// // The only valid value of this type is the bytes `0xC0C0`.
1739-
/// #[derive(TryFromBytes, KnownLayout)]
1739+
/// #[derive(TryFromBytes, IntoBytes, KnownLayout)]
17401740
/// #[repr(C)]
17411741
/// struct C0C0(C0, C0);
17421742
///
1743-
/// #[derive(TryFromBytes, KnownLayout)]
1744-
/// #[repr(C)]
1743+
/// #[derive(TryFromBytes, IntoBytes, KnownLayout)]
1744+
/// #[repr(C, packed)]
17451745
/// struct Packet {
17461746
/// magic_number: C0C0,
17471747
/// mug_size: u8,
@@ -1769,7 +1769,7 @@ pub unsafe trait TryFromBytes {
17691769
#[inline]
17701770
fn try_mut_from_bytes(bytes: &mut [u8]) -> Result<&mut Self, TryCastError<&mut [u8], Self>>
17711771
where
1772-
Self: KnownLayout,
1772+
Self: KnownLayout + IntoBytes,
17731773
{
17741774
static_assert_dst_is_not_zst!(Self);
17751775
match Ptr::from_mut(bytes).try_cast_into_no_leftover::<Self, BecauseExclusive>(None) {
@@ -1821,8 +1821,8 @@ pub unsafe trait TryFromBytes {
18211821
/// use zerocopy::*;
18221822
/// # use zerocopy_derive::*;
18231823
///
1824-
/// #[derive(TryFromBytes, KnownLayout)]
1825-
/// #[repr(C)]
1824+
/// #[derive(TryFromBytes, IntoBytes, KnownLayout)]
1825+
/// #[repr(C, packed)]
18261826
/// struct ZSTy {
18271827
/// leading_sized: [u8; 2],
18281828
/// trailing_dst: [()],
@@ -1839,17 +1839,17 @@ pub unsafe trait TryFromBytes {
18391839
/// # use zerocopy_derive::*;
18401840
///
18411841
/// // The only valid value of this type is the byte `0xC0`
1842-
/// #[derive(TryFromBytes, KnownLayout)]
1842+
/// #[derive(TryFromBytes, IntoBytes, KnownLayout)]
18431843
/// #[repr(u8)]
18441844
/// enum C0 { xC0 = 0xC0 }
18451845
///
18461846
/// // The only valid value of this type is the bytes `0xC0C0`.
1847-
/// #[derive(TryFromBytes, KnownLayout)]
1847+
/// #[derive(TryFromBytes, IntoBytes, KnownLayout)]
18481848
/// #[repr(C)]
18491849
/// struct C0C0(C0, C0);
18501850
///
1851-
/// #[derive(TryFromBytes, KnownLayout)]
1852-
/// #[repr(C)]
1851+
/// #[derive(TryFromBytes, IntoBytes, KnownLayout)]
1852+
/// #[repr(C, packed)]
18531853
/// struct Packet {
18541854
/// magic_number: C0C0,
18551855
/// mug_size: u8,
@@ -1882,7 +1882,7 @@ pub unsafe trait TryFromBytes {
18821882
source: &mut [u8],
18831883
) -> Result<(&mut Self, &mut [u8]), TryCastError<&mut [u8], Self>>
18841884
where
1885-
Self: KnownLayout,
1885+
Self: KnownLayout + IntoBytes,
18861886
{
18871887
static_assert_dst_is_not_zst!(Self);
18881888
try_mut_from_prefix_suffix(source, CastType::Prefix, None)
@@ -1916,8 +1916,8 @@ pub unsafe trait TryFromBytes {
19161916
/// use zerocopy::*;
19171917
/// # use zerocopy_derive::*;
19181918
///
1919-
/// #[derive(TryFromBytes, KnownLayout)]
1920-
/// #[repr(C)]
1919+
/// #[derive(TryFromBytes, IntoBytes, KnownLayout)]
1920+
/// #[repr(C, packed)]
19211921
/// struct ZSTy {
19221922
/// leading_sized: u16,
19231923
/// trailing_dst: [()],
@@ -1934,17 +1934,17 @@ pub unsafe trait TryFromBytes {
19341934
/// # use zerocopy_derive::*;
19351935
///
19361936
/// // The only valid value of this type is the byte `0xC0`
1937-
/// #[derive(TryFromBytes, KnownLayout)]
1937+
/// #[derive(TryFromBytes, IntoBytes, KnownLayout)]
19381938
/// #[repr(u8)]
19391939
/// enum C0 { xC0 = 0xC0 }
19401940
///
19411941
/// // The only valid value of this type is the bytes `0xC0C0`.
1942-
/// #[derive(TryFromBytes, KnownLayout)]
1942+
/// #[derive(TryFromBytes, IntoBytes, KnownLayout)]
19431943
/// #[repr(C)]
19441944
/// struct C0C0(C0, C0);
19451945
///
1946-
/// #[derive(TryFromBytes, KnownLayout)]
1947-
/// #[repr(C)]
1946+
/// #[derive(TryFromBytes, IntoBytes, KnownLayout)]
1947+
/// #[repr(C, packed)]
19481948
/// struct Packet {
19491949
/// magic_number: C0C0,
19501950
/// mug_size: u8,
@@ -1977,7 +1977,7 @@ pub unsafe trait TryFromBytes {
19771977
source: &mut [u8],
19781978
) -> Result<(&mut [u8], &mut Self), TryCastError<&mut [u8], Self>>
19791979
where
1980-
Self: KnownLayout,
1980+
Self: KnownLayout + IntoBytes,
19811981
{
19821982
static_assert_dst_is_not_zst!(Self);
19831983
try_mut_from_prefix_suffix(source, CastType::Suffix, None).map(swap)
@@ -2286,17 +2286,17 @@ pub unsafe trait TryFromBytes {
22862286
/// # use zerocopy_derive::*;
22872287
///
22882288
/// // The only valid value of this type is the byte `0xC0`
2289-
/// #[derive(TryFromBytes, KnownLayout)]
2289+
/// #[derive(TryFromBytes, IntoBytes, KnownLayout)]
22902290
/// #[repr(u8)]
22912291
/// enum C0 { xC0 = 0xC0 }
22922292
///
22932293
/// // The only valid value of this type is the bytes `0xC0C0`.
2294-
/// #[derive(TryFromBytes, KnownLayout)]
2294+
/// #[derive(TryFromBytes, IntoBytes, KnownLayout)]
22952295
/// #[repr(C)]
22962296
/// struct C0C0(C0, C0);
22972297
///
2298-
/// #[derive(TryFromBytes, KnownLayout)]
2299-
/// #[repr(C)]
2298+
/// #[derive(TryFromBytes, IntoBytes, KnownLayout)]
2299+
/// #[repr(C, packed)]
23002300
/// struct Packet {
23012301
/// magic_number: C0C0,
23022302
/// mug_size: u8,
@@ -2330,8 +2330,8 @@ pub unsafe trait TryFromBytes {
23302330
/// use zerocopy::*;
23312331
/// # use zerocopy_derive::*;
23322332
///
2333-
/// #[derive(TryFromBytes, KnownLayout)]
2334-
/// #[repr(C)]
2333+
/// #[derive(TryFromBytes, IntoBytes, KnownLayout)]
2334+
/// #[repr(C, packed)]
23352335
/// struct ZSTy {
23362336
/// leading_sized: NonZeroU16,
23372337
/// trailing_dst: [()],
@@ -2351,7 +2351,7 @@ pub unsafe trait TryFromBytes {
23512351
count: usize,
23522352
) -> Result<&mut Self, TryCastError<&mut [u8], Self>>
23532353
where
2354-
Self: KnownLayout<PointerMetadata = usize>,
2354+
Self: KnownLayout<PointerMetadata = usize> + IntoBytes,
23552355
{
23562356
match Ptr::from_mut(source).try_cast_into_no_leftover::<Self, BecauseExclusive>(Some(count))
23572357
{
@@ -2397,17 +2397,17 @@ pub unsafe trait TryFromBytes {
23972397
/// # use zerocopy_derive::*;
23982398
///
23992399
/// // The only valid value of this type is the byte `0xC0`
2400-
/// #[derive(TryFromBytes, KnownLayout)]
2400+
/// #[derive(TryFromBytes, IntoBytes, KnownLayout)]
24012401
/// #[repr(u8)]
24022402
/// enum C0 { xC0 = 0xC0 }
24032403
///
24042404
/// // The only valid value of this type is the bytes `0xC0C0`.
2405-
/// #[derive(TryFromBytes, KnownLayout)]
2405+
/// #[derive(TryFromBytes, IntoBytes, KnownLayout)]
24062406
/// #[repr(C)]
24072407
/// struct C0C0(C0, C0);
24082408
///
2409-
/// #[derive(TryFromBytes, KnownLayout)]
2410-
/// #[repr(C)]
2409+
/// #[derive(TryFromBytes, IntoBytes, KnownLayout)]
2410+
/// #[repr(C, packed)]
24112411
/// struct Packet {
24122412
/// magic_number: C0C0,
24132413
/// mug_size: u8,
@@ -2443,8 +2443,8 @@ pub unsafe trait TryFromBytes {
24432443
/// use zerocopy::*;
24442444
/// # use zerocopy_derive::*;
24452445
///
2446-
/// #[derive(TryFromBytes, KnownLayout)]
2447-
/// #[repr(C)]
2446+
/// #[derive(TryFromBytes, IntoBytes, KnownLayout)]
2447+
/// #[repr(C, packed)]
24482448
/// struct ZSTy {
24492449
/// leading_sized: NonZeroU16,
24502450
/// trailing_dst: [()],
@@ -2464,7 +2464,7 @@ pub unsafe trait TryFromBytes {
24642464
count: usize,
24652465
) -> Result<(&mut Self, &mut [u8]), TryCastError<&mut [u8], Self>>
24662466
where
2467-
Self: KnownLayout<PointerMetadata = usize>,
2467+
Self: KnownLayout<PointerMetadata = usize> + IntoBytes,
24682468
{
24692469
try_mut_from_prefix_suffix(source, CastType::Prefix, Some(count))
24702470
}
@@ -2492,17 +2492,17 @@ pub unsafe trait TryFromBytes {
24922492
/// # use zerocopy_derive::*;
24932493
///
24942494
/// // The only valid value of this type is the byte `0xC0`
2495-
/// #[derive(TryFromBytes, KnownLayout)]
2495+
/// #[derive(TryFromBytes, IntoBytes, KnownLayout)]
24962496
/// #[repr(u8)]
24972497
/// enum C0 { xC0 = 0xC0 }
24982498
///
24992499
/// // The only valid value of this type is the bytes `0xC0C0`.
2500-
/// #[derive(TryFromBytes, KnownLayout)]
2500+
/// #[derive(TryFromBytes, IntoBytes, KnownLayout)]
25012501
/// #[repr(C)]
25022502
/// struct C0C0(C0, C0);
25032503
///
2504-
/// #[derive(TryFromBytes, KnownLayout)]
2505-
/// #[repr(C)]
2504+
/// #[derive(TryFromBytes, IntoBytes, KnownLayout)]
2505+
/// #[repr(C, packed)]
25062506
/// struct Packet {
25072507
/// magic_number: C0C0,
25082508
/// mug_size: u8,
@@ -2538,8 +2538,8 @@ pub unsafe trait TryFromBytes {
25382538
/// use zerocopy::*;
25392539
/// # use zerocopy_derive::*;
25402540
///
2541-
/// #[derive(TryFromBytes, KnownLayout)]
2542-
/// #[repr(C)]
2541+
/// #[derive(TryFromBytes, IntoBytes, KnownLayout)]
2542+
/// #[repr(C, packed)]
25432543
/// struct ZSTy {
25442544
/// leading_sized: NonZeroU16,
25452545
/// trailing_dst: [()],
@@ -2559,7 +2559,7 @@ pub unsafe trait TryFromBytes {
25592559
count: usize,
25602560
) -> Result<(&mut [u8], &mut Self), TryCastError<&mut [u8], Self>>
25612561
where
2562-
Self: KnownLayout<PointerMetadata = usize>,
2562+
Self: KnownLayout<PointerMetadata = usize> + IntoBytes,
25632563
{
25642564
try_mut_from_prefix_suffix(source, CastType::Suffix, Some(count)).map(swap)
25652565
}
@@ -2771,7 +2771,7 @@ fn try_ref_from_prefix_suffix<T: TryFromBytes + KnownLayout + Immutable + ?Sized
27712771
}
27722772

27732773
#[inline(always)]
2774-
fn try_mut_from_prefix_suffix<T: TryFromBytes + KnownLayout + ?Sized>(
2774+
fn try_mut_from_prefix_suffix<T: IntoBytes + TryFromBytes + KnownLayout + ?Sized>(
27752775
candidate: &mut [u8],
27762776
cast_type: CastType,
27772777
meta: Option<T::PointerMetadata>,

src/macros.rs

+11-11
Original file line numberDiff line numberDiff line change
@@ -249,8 +249,8 @@ macro_rules! transmute_ref {
249249
/// const fn transmute_mut<'src, 'dst, Src, Dst>(src: &'src mut Src) -> &'dst mut Dst
250250
/// where
251251
/// 'src: 'dst,
252-
/// Src: FromBytes + IntoBytes + Immutable,
253-
/// Dst: FromBytes + IntoBytes + Immutable,
252+
/// Src: FromBytes + IntoBytes,
253+
/// Dst: FromBytes + IntoBytes,
254254
/// size_of::<Src>() == size_of::<Dst>(),
255255
/// align_of::<Src>() >= align_of::<Dst>(),
256256
/// {
@@ -325,9 +325,9 @@ macro_rules! transmute_mut {
325325
#[allow(unused, clippy::diverging_sub_expression)]
326326
if false {
327327
// This branch, though never taken, ensures that the type of `e` is
328-
// `&mut T` where `T: 't + Sized + FromBytes + IntoBytes + Immutable`
329-
// and that the type of this macro expression is `&mut U` where `U:
330-
// 'u + Sized + FromBytes + IntoBytes + Immutable`.
328+
// `&mut T` where `T: 't + Sized + FromBytes + IntoBytes` and that
329+
// the type of this macro expression is `&mut U` where `U: 'u +
330+
// Sized + FromBytes + IntoBytes`.
331331

332332
// We use immutable references here rather than mutable so that, if
333333
// this macro is used in a const context (in which, as of this
@@ -577,8 +577,8 @@ macro_rules! try_transmute_ref {
577577
/// ```ignore
578578
/// fn try_transmute_mut<Src, Dst>(src: &mut Src) -> Result<&mut Dst, ValidityError<&mut Src, Dst>>
579579
/// where
580-
/// Src: IntoBytes,
581-
/// Dst: TryFromBytes,
580+
/// Src: FromBytes + IntoBytes,
581+
/// Dst: TryFromBytes + IntoBytes,
582582
/// size_of::<Src>() == size_of::<Dst>(),
583583
/// align_of::<Src>() >= align_of::<Dst>(),
584584
/// {
@@ -888,9 +888,9 @@ mod tests {
888888
#[test]
889889
fn test_try_transmute_mut() {
890890
// Test that memory is transmuted with `try_transmute_mut` as expected.
891-
let array_of_bools = &mut [false, true, false, true, false, true, false, true];
891+
let array_of_u8s = &mut [0u8, 1, 0, 1, 0, 1, 0, 1];
892892
let array_of_arrays = &mut [[0u8, 1], [0, 1], [0, 1], [0, 1]];
893-
let x: Result<&mut [[u8; 2]; 4], _> = try_transmute_mut!(array_of_bools);
893+
let x: Result<&mut [[u8; 2]; 4], _> = try_transmute_mut!(array_of_u8s);
894894
assert_eq!(x, Ok(array_of_arrays));
895895

896896
let array_of_bools = &mut [false, true, false, true, false, true, false, true];
@@ -903,8 +903,8 @@ mod tests {
903903
let array_of_bools = &mut [false, true, false, true, false, true, false, true];
904904
let array_of_arrays = &mut [[0u8, 1], [0, 1], [0, 1], [0, 1]];
905905
{
906-
let x: Result<&mut [[u8; 2]; 4], _> = try_transmute_mut!(array_of_bools);
907-
assert_eq!(x, Ok(array_of_arrays));
906+
let x: Result<&mut [bool; 8], _> = try_transmute_mut!(array_of_arrays);
907+
assert_eq!(x, Ok(array_of_bools));
908908
}
909909

910910
// Test that `try_transmute_mut!` supports decreasing alignment.

0 commit comments

Comments
 (0)