Skip to content

Commit

Permalink
Enforce Src: FromBytes in try_transmute_mut!
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.

Fixes #2226
  • Loading branch information
jswrenn committed Jan 12, 2025
1 parent 2c8ef74 commit 69ad562
Show file tree
Hide file tree
Showing 12 changed files with 558 additions and 50 deletions.
2 changes: 1 addition & 1 deletion 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: FromByte + IntoBytes,
/// Dst: TryFromBytes,
/// size_of::<Src>() == size_of::<Dst>(),
/// align_of::<Src>() >= align_of::<Dst>(),
Expand Down
4 changes: 2 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 @@ -675,7 +675,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
59 changes: 59 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,59 @@
warning: unnecessary trailing semicolon
--> tests/ui-msrv/try_transmute_mut-src-not-frombytes.rs:23:65
|
23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
| ^ help: remove this semicolon
|
= note: `#[warn(redundant_semicolons)]` on by default

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);
}
112 changes: 112 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,112 @@
warning: unnecessary trailing semicolon
--> tests/ui-nightly/try_transmute_mut-src-not-frombytes.rs:23:65
|
23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
| ^ help: remove this semicolon
|
= note: `#[warn(redundant_semicolons)]` on by default

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 69ad562

Please sign in to comment.