Skip to content

Commit

Permalink
Enforce Src: FromBytes in try_transmute_mut! (#2229)
Browse files Browse the repository at this point in the history
Ensures that the source reference remains valid after the
transmuted (and possibly mutated)  destination is dropped.

Makes progress on #2226
  • Loading branch information
jswrenn authored Feb 4, 2025
1 parent 3ad056b commit 118b6f3
Show file tree
Hide file tree
Showing 12 changed files with 540 additions and 54 deletions.
10 changes: 5 additions & 5 deletions src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -577,7 +577,7 @@ macro_rules! try_transmute_ref {
/// ```ignore
/// fn try_transmute_mut<Src, Dst>(src: &mut Src) -> Result<&mut Dst, ValidityError<&mut Src, Dst>>
/// where
/// Src: IntoBytes,
/// Src: FromBytes + IntoBytes,
/// Dst: TryFromBytes,
/// size_of::<Src>() == size_of::<Dst>(),
/// align_of::<Src>() >= align_of::<Dst>(),
Expand Down Expand Up @@ -888,9 +888,9 @@ mod tests {
#[test]
fn test_try_transmute_mut() {
// Test that memory is transmuted with `try_transmute_mut` as expected.
let array_of_bools = &mut [false, true, false, true, false, true, false, true];
let array_of_u8s = &mut [0u8, 1, 0, 1, 0, 1, 0, 1];
let array_of_arrays = &mut [[0u8, 1], [0, 1], [0, 1], [0, 1]];
let x: Result<&mut [[u8; 2]; 4], _> = try_transmute_mut!(array_of_bools);
let x: Result<&mut [[u8; 2]; 4], _> = try_transmute_mut!(array_of_u8s);
assert_eq!(x, Ok(array_of_arrays));

let array_of_bools = &mut [false, true, false, true, false, true, false, true];
Expand All @@ -903,8 +903,8 @@ mod tests {
let array_of_bools = &mut [false, true, false, true, false, true, false, true];
let array_of_arrays = &mut [[0u8, 1], [0, 1], [0, 1], [0, 1]];
{
let x: Result<&mut [[u8; 2]; 4], _> = try_transmute_mut!(array_of_bools);
assert_eq!(x, Ok(array_of_arrays));
let x: Result<&mut [bool; 8], _> = try_transmute_mut!(array_of_arrays);
assert_eq!(x, Ok(array_of_bools));
}

// Test that `try_transmute_mut!` supports decreasing alignment.
Expand Down
6 changes: 4 additions & 2 deletions src/util/macro_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use crate::{
invariant::{self, AtLeast, Invariants},
AliasingSafe, AliasingSafeReason, BecauseExclusive, BecauseImmutable,
},
Immutable, IntoBytes, Ptr, TryFromBytes, Unalign, ValidityError,
FromBytes, Immutable, IntoBytes, Ptr, TryFromBytes, Unalign, ValidityError,
};

/// Projects the type of the field at `Index` in `Self`.
Expand Down Expand Up @@ -552,6 +552,8 @@ fn try_cast_or_pme<Src, Dst, I, R>(
ValidityError<Ptr<'_, Src, I>, Dst>,
>
where
// TODO(#2226): There should be a `Src: FromBytes` bound here, but doing so
// requires deeper surgery.
Src: IntoBytes,
Dst: TryFromBytes + AliasingSafe<Src, I::Aliasing, R>,
I: Invariants<Validity = invariant::Valid>,
Expand Down Expand Up @@ -681,7 +683,7 @@ where
#[inline(always)]
pub fn try_transmute_mut<Src, Dst>(src: &mut Src) -> Result<&mut Dst, ValidityError<&mut Src, Dst>>
where
Src: IntoBytes,
Src: FromBytes + IntoBytes,
Dst: TryFromBytes,
{
match try_cast_or_pme::<Src, Dst, _, BecauseExclusive>(Ptr::from_mut(src)) {
Expand Down
1 change: 1 addition & 0 deletions tests/ui-msrv/try_transmute_mut-src-not-frombytes.rs
51 changes: 51 additions & 0 deletions tests/ui-msrv/try_transmute_mut-src-not-frombytes.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
error[E0277]: the trait bound `Src: FromBytes` is not satisfied
--> tests/ui-msrv/try_transmute_mut-src-not-frombytes.rs:23:40
|
23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `Src`
|
note: required by `AssertSrcIsFromBytes`
--> tests/ui-msrv/try_transmute_mut-src-not-frombytes.rs:23:40
|
23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
| ^^^^^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `Src: FromBytes` is not satisfied
--> tests/ui-msrv/try_transmute_mut-src-not-frombytes.rs:23:40
|
23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `Src`
|
note: required by a bound in `AssertSrcIsFromBytes`
--> tests/ui-msrv/try_transmute_mut-src-not-frombytes.rs:23:40
|
23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
| ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsFromBytes`
= note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `Dst: FromBytes` is not satisfied
--> tests/ui-msrv/try_transmute_mut-src-not-frombytes.rs:23:40
|
23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `Dst`
|
note: required by `AssertDstIsFromBytes`
--> tests/ui-msrv/try_transmute_mut-src-not-frombytes.rs:23:40
|
23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
| ^^^^^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `Dst: IntoBytes` is not satisfied
--> tests/ui-msrv/try_transmute_mut-src-not-frombytes.rs:23:40
|
23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `IntoBytes` is not implemented for `Dst`
|
note: required by `AssertDstIsIntoBytes`
--> tests/ui-msrv/try_transmute_mut-src-not-frombytes.rs:23:40
|
23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
| ^^^^^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
57 changes: 48 additions & 9 deletions tests/ui-msrv/try_transmute_mut-src-not-intobytes.stderr
Original file line number Diff line number Diff line change
@@ -1,12 +1,51 @@
error[E0277]: the trait bound `NotZerocopy<AU16>: zerocopy::IntoBytes` is not satisfied
--> tests/ui-msrv/try_transmute_mut-src-not-intobytes.rs:19:52
error[E0277]: the trait bound `Src: IntoBytes` is not satisfied
--> tests/ui-msrv/try_transmute_mut-src-not-intobytes.rs:23:40
|
19 | let src_not_into_bytes: Result<&mut AU16, _> = try_transmute_mut!(src);
| ^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy<AU16>`
23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `IntoBytes` is not implemented for `Src`
|
note: required by a bound in `try_transmute_mut`
--> src/util/macro_util.rs
note: required by `AssertSrcIsIntoBytes`
--> tests/ui-msrv/try_transmute_mut-src-not-intobytes.rs:23:40
|
| Src: IntoBytes,
| ^^^^^^^^^ required by this bound in `try_transmute_mut`
= note: this error originates in the macro `try_transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
| ^^^^^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `Src: IntoBytes` is not satisfied
--> tests/ui-msrv/try_transmute_mut-src-not-intobytes.rs:23:40
|
23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `IntoBytes` is not implemented for `Src`
|
note: required by a bound in `AssertSrcIsIntoBytes`
--> tests/ui-msrv/try_transmute_mut-src-not-intobytes.rs:23:40
|
23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
| ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsIntoBytes`
= note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `Dst: FromBytes` is not satisfied
--> tests/ui-msrv/try_transmute_mut-src-not-intobytes.rs:23:40
|
23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `Dst`
|
note: required by `AssertDstIsFromBytes`
--> tests/ui-msrv/try_transmute_mut-src-not-intobytes.rs:23:40
|
23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
| ^^^^^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `Dst: IntoBytes` is not satisfied
--> tests/ui-msrv/try_transmute_mut-src-not-intobytes.rs:23:40
|
23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `IntoBytes` is not implemented for `Dst`
|
note: required by `AssertDstIsIntoBytes`
--> tests/ui-msrv/try_transmute_mut-src-not-intobytes.rs:23:40
|
23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
| ^^^^^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
24 changes: 24 additions & 0 deletions tests/ui-nightly/try_transmute_mut-src-not-frombytes.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright 2024 The Fuchsia Authors
//
// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
// This file may not be copied, modified, or distributed except according to
// those terms.

extern crate zerocopy;

use zerocopy::transmute_mut;

#[derive(zerocopy::IntoBytes)]
#[repr(C)]
struct Src;

#[derive(zerocopy::TryFromBytes)]
#[repr(C)]
struct Dst;

fn main() {
// `try_transmute_mut` requires that the source type implements `FromBytes`
let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
}
104 changes: 104 additions & 0 deletions tests/ui-nightly/try_transmute_mut-src-not-frombytes.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
error[E0277]: the trait bound `Src: FromBytes` is not satisfied
--> tests/ui-nightly/try_transmute_mut-src-not-frombytes.rs:23:40
|
23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
| ^^^^^^^^^^^^^^^^^^^^^^^^
| |
| the trait `FromBytes` is not implemented for `Src`
| required by a bound introduced by this call
|
= note: Consider adding `#[derive(FromBytes)]` to `Src`
= help: the following other types implement trait `FromBytes`:
()
AtomicI16
AtomicI32
AtomicI64
AtomicI8
AtomicIsize
AtomicU16
AtomicU32
and $N others
note: required by a bound in `AssertSrcIsFromBytes`
--> tests/ui-nightly/try_transmute_mut-src-not-frombytes.rs:23:40
|
23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
| ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsFromBytes`
= note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `Src: FromBytes` is not satisfied
--> tests/ui-nightly/try_transmute_mut-src-not-frombytes.rs:23:40
|
23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `Src`
|
= note: Consider adding `#[derive(FromBytes)]` to `Src`
= help: the following other types implement trait `FromBytes`:
()
AtomicI16
AtomicI32
AtomicI64
AtomicI8
AtomicIsize
AtomicU16
AtomicU32
and $N others
note: required by a bound in `AssertSrcIsFromBytes`
--> tests/ui-nightly/try_transmute_mut-src-not-frombytes.rs:23:40
|
23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
| ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsFromBytes`
= note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `Dst: FromBytes` is not satisfied
--> tests/ui-nightly/try_transmute_mut-src-not-frombytes.rs:23:40
|
23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
| ^^^^^^^^^^^^^^^^^^^^^^^^
| |
| the trait `FromBytes` is not implemented for `Dst`
| required by a bound introduced by this call
|
= note: Consider adding `#[derive(FromBytes)]` to `Dst`
= help: the following other types implement trait `FromBytes`:
()
AtomicI16
AtomicI32
AtomicI64
AtomicI8
AtomicIsize
AtomicU16
AtomicU32
and $N others
note: required by a bound in `AssertDstIsFromBytes`
--> tests/ui-nightly/try_transmute_mut-src-not-frombytes.rs:23:40
|
23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
| ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsFromBytes`
= note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `Dst: IntoBytes` is not satisfied
--> tests/ui-nightly/try_transmute_mut-src-not-frombytes.rs:23:40
|
23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
| ^^^^^^^^^^^^^^^^^^^^^^^^
| |
| the trait `IntoBytes` is not implemented for `Dst`
| required by a bound introduced by this call
|
= note: Consider adding `#[derive(IntoBytes)]` to `Dst`
= help: the following other types implement trait `IntoBytes`:
()
AtomicBool
AtomicI16
AtomicI32
AtomicI64
AtomicI8
AtomicIsize
AtomicU16
and $N others
note: required by a bound in `AssertDstIsIntoBytes`
--> tests/ui-nightly/try_transmute_mut-src-not-frombytes.rs:23:40
|
23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
| ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsIntoBytes`
= note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
16 changes: 10 additions & 6 deletions tests/ui-nightly/try_transmute_mut-src-not-intobytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,19 @@
// This file may not be copied, modified, or distributed except according to
// those terms.

include!("../../zerocopy-derive/tests/include.rs");

extern crate zerocopy;

use util::{NotZerocopy, AU16};
use zerocopy::try_transmute_mut;
use zerocopy::transmute_mut;

#[derive(zerocopy::FromBytes)]
#[repr(C)]
struct Src;

#[derive(zerocopy::TryFromBytes)]
#[repr(C)]
struct Dst;

fn main() {
// `try_transmute_mut` requires that the source type implements `IntoBytes`
let src = &mut NotZerocopy(AU16(0));
let src_not_into_bytes: Result<&mut AU16, _> = try_transmute_mut!(src);
let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
}
Loading

0 comments on commit 118b6f3

Please sign in to comment.