Skip to content

Commit cc95f58

Browse files
committed
Enforce Src: FromBytes in try_transmute_mut!
Ensures that the source reference remains valid after the transmuted (and possibly mutated) destination is dropped. Makes progress on #2226
1 parent 2c8ef74 commit cc95f58

12 files changed

+538
-57
lines changed

src/macros.rs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -577,7 +577,7 @@ 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,
580+
/// Src: FromBytes + IntoBytes,
581581
/// Dst: TryFromBytes,
582582
/// size_of::<Src>() == size_of::<Dst>(),
583583
/// align_of::<Src>() >= align_of::<Dst>(),
@@ -888,11 +888,6 @@ 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];
892-
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);
894-
assert_eq!(x, Ok(array_of_arrays));
895-
896891
let array_of_bools = &mut [false, true, false, true, false, true, false, true];
897892
let array_of_arrays = &mut [[0u8, 1], [0, 1], [0, 1], [0, 1]];
898893
let x: Result<&mut [bool; 8], _> = try_transmute_mut!(array_of_arrays);
@@ -903,8 +898,8 @@ mod tests {
903898
let array_of_bools = &mut [false, true, false, true, false, true, false, true];
904899
let array_of_arrays = &mut [[0u8, 1], [0, 1], [0, 1], [0, 1]];
905900
{
906-
let x: Result<&mut [[u8; 2]; 4], _> = try_transmute_mut!(array_of_bools);
907-
assert_eq!(x, Ok(array_of_arrays));
901+
let x: Result<&mut [bool; 8], _> = try_transmute_mut!(array_of_arrays);
902+
assert_eq!(x, Ok(array_of_bools));
908903
}
909904

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

src/util/macro_util.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ use crate::{
2929
invariant::{self, AtLeast, Invariants},
3030
AliasingSafe, AliasingSafeReason, BecauseExclusive, BecauseImmutable,
3131
},
32-
Immutable, IntoBytes, Ptr, TryFromBytes, Unalign, ValidityError,
32+
FromBytes, Immutable, IntoBytes, Ptr, TryFromBytes, Unalign, ValidityError,
3333
};
3434

3535
/// Projects the type of the field at `Index` in `Self`.
@@ -546,6 +546,8 @@ fn try_cast_or_pme<Src, Dst, I, R>(
546546
ValidityError<Ptr<'_, Src, I>, Dst>,
547547
>
548548
where
549+
// TODO(#2226): There should be a `Src: FromBytes` bound here, but doing so
550+
// requires deeper surgery.
549551
Src: IntoBytes,
550552
Dst: TryFromBytes + AliasingSafe<Src, I::Aliasing, R>,
551553
I: Invariants<Validity = invariant::Valid>,
@@ -675,7 +677,7 @@ where
675677
#[inline(always)]
676678
pub fn try_transmute_mut<Src, Dst>(src: &mut Src) -> Result<&mut Dst, ValidityError<&mut Src, Dst>>
677679
where
678-
Src: IntoBytes,
680+
Src: FromBytes + IntoBytes,
679681
Dst: TryFromBytes,
680682
{
681683
match try_cast_or_pme::<Src, Dst, _, BecauseExclusive>(Ptr::from_mut(src)) {
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../ui-nightly/try_transmute_mut-src-not-frombytes.rs
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
error[E0277]: the trait bound `Src: FromBytes` is not satisfied
2+
--> tests/ui-msrv/try_transmute_mut-src-not-frombytes.rs:23:40
3+
|
4+
23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `Src`
6+
|
7+
note: required by `AssertSrcIsFromBytes`
8+
--> tests/ui-msrv/try_transmute_mut-src-not-frombytes.rs:23:40
9+
|
10+
23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^
12+
= note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
13+
14+
error[E0277]: the trait bound `Src: FromBytes` is not satisfied
15+
--> tests/ui-msrv/try_transmute_mut-src-not-frombytes.rs:23:40
16+
|
17+
23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
18+
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `Src`
19+
|
20+
note: required by a bound in `AssertSrcIsFromBytes`
21+
--> tests/ui-msrv/try_transmute_mut-src-not-frombytes.rs:23:40
22+
|
23+
23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
24+
| ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsFromBytes`
25+
= note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
26+
27+
error[E0277]: the trait bound `Dst: FromBytes` is not satisfied
28+
--> tests/ui-msrv/try_transmute_mut-src-not-frombytes.rs:23:40
29+
|
30+
23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
31+
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `Dst`
32+
|
33+
note: required by `AssertDstIsFromBytes`
34+
--> tests/ui-msrv/try_transmute_mut-src-not-frombytes.rs:23:40
35+
|
36+
23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
37+
| ^^^^^^^^^^^^^^^^^^^^^^^^
38+
= note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
39+
40+
error[E0277]: the trait bound `Dst: IntoBytes` is not satisfied
41+
--> tests/ui-msrv/try_transmute_mut-src-not-frombytes.rs:23:40
42+
|
43+
23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
44+
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `IntoBytes` is not implemented for `Dst`
45+
|
46+
note: required by `AssertDstIsIntoBytes`
47+
--> tests/ui-msrv/try_transmute_mut-src-not-frombytes.rs:23:40
48+
|
49+
23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
50+
| ^^^^^^^^^^^^^^^^^^^^^^^^
51+
= note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,51 @@
1-
error[E0277]: the trait bound `NotZerocopy<AU16>: zerocopy::IntoBytes` is not satisfied
2-
--> tests/ui-msrv/try_transmute_mut-src-not-intobytes.rs:19:52
1+
error[E0277]: the trait bound `Src: IntoBytes` is not satisfied
2+
--> tests/ui-msrv/try_transmute_mut-src-not-intobytes.rs:23:40
33
|
4-
19 | let src_not_into_bytes: Result<&mut AU16, _> = try_transmute_mut!(src);
5-
| ^^^^^^^^^^^^^^^^^^^^^^^ the trait `zerocopy::IntoBytes` is not implemented for `NotZerocopy<AU16>`
4+
23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `IntoBytes` is not implemented for `Src`
66
|
7-
note: required by a bound in `try_transmute_mut`
8-
--> src/util/macro_util.rs
7+
note: required by `AssertSrcIsIntoBytes`
8+
--> tests/ui-msrv/try_transmute_mut-src-not-intobytes.rs:23:40
99
|
10-
| Src: IntoBytes,
11-
| ^^^^^^^^^ required by this bound in `try_transmute_mut`
12-
= note: this error originates in the macro `try_transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
10+
23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^
12+
= note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
13+
14+
error[E0277]: the trait bound `Src: IntoBytes` is not satisfied
15+
--> tests/ui-msrv/try_transmute_mut-src-not-intobytes.rs:23:40
16+
|
17+
23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
18+
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `IntoBytes` is not implemented for `Src`
19+
|
20+
note: required by a bound in `AssertSrcIsIntoBytes`
21+
--> tests/ui-msrv/try_transmute_mut-src-not-intobytes.rs:23:40
22+
|
23+
23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
24+
| ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsIntoBytes`
25+
= note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
26+
27+
error[E0277]: the trait bound `Dst: FromBytes` is not satisfied
28+
--> tests/ui-msrv/try_transmute_mut-src-not-intobytes.rs:23:40
29+
|
30+
23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
31+
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `Dst`
32+
|
33+
note: required by `AssertDstIsFromBytes`
34+
--> tests/ui-msrv/try_transmute_mut-src-not-intobytes.rs:23:40
35+
|
36+
23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
37+
| ^^^^^^^^^^^^^^^^^^^^^^^^
38+
= note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
39+
40+
error[E0277]: the trait bound `Dst: IntoBytes` is not satisfied
41+
--> tests/ui-msrv/try_transmute_mut-src-not-intobytes.rs:23:40
42+
|
43+
23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
44+
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `IntoBytes` is not implemented for `Dst`
45+
|
46+
note: required by `AssertDstIsIntoBytes`
47+
--> tests/ui-msrv/try_transmute_mut-src-not-intobytes.rs:23:40
48+
|
49+
23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
50+
| ^^^^^^^^^^^^^^^^^^^^^^^^
51+
= note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright 2024 The Fuchsia Authors
2+
//
3+
// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
4+
// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
5+
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
6+
// This file may not be copied, modified, or distributed except according to
7+
// those terms.
8+
9+
extern crate zerocopy;
10+
11+
use zerocopy::transmute_mut;
12+
13+
#[derive(zerocopy::IntoBytes)]
14+
#[repr(C)]
15+
struct Src;
16+
17+
#[derive(zerocopy::TryFromBytes)]
18+
#[repr(C)]
19+
struct Dst;
20+
21+
fn main() {
22+
// `try_transmute_mut` requires that the source type implements `FromBytes`
23+
let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
24+
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
error[E0277]: the trait bound `Src: FromBytes` is not satisfied
2+
--> tests/ui-nightly/try_transmute_mut-src-not-frombytes.rs:23:40
3+
|
4+
23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^
6+
| |
7+
| the trait `FromBytes` is not implemented for `Src`
8+
| required by a bound introduced by this call
9+
|
10+
= note: Consider adding `#[derive(FromBytes)]` to `Src`
11+
= help: the following other types implement trait `FromBytes`:
12+
()
13+
AtomicI16
14+
AtomicI32
15+
AtomicI64
16+
AtomicI8
17+
AtomicIsize
18+
AtomicU16
19+
AtomicU32
20+
and $N others
21+
note: required by a bound in `AssertSrcIsFromBytes`
22+
--> tests/ui-nightly/try_transmute_mut-src-not-frombytes.rs:23:40
23+
|
24+
23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
25+
| ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsFromBytes`
26+
= note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
27+
28+
error[E0277]: the trait bound `Src: FromBytes` is not satisfied
29+
--> tests/ui-nightly/try_transmute_mut-src-not-frombytes.rs:23:40
30+
|
31+
23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
32+
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `Src`
33+
|
34+
= note: Consider adding `#[derive(FromBytes)]` to `Src`
35+
= help: the following other types implement trait `FromBytes`:
36+
()
37+
AtomicI16
38+
AtomicI32
39+
AtomicI64
40+
AtomicI8
41+
AtomicIsize
42+
AtomicU16
43+
AtomicU32
44+
and $N others
45+
note: required by a bound in `AssertSrcIsFromBytes`
46+
--> tests/ui-nightly/try_transmute_mut-src-not-frombytes.rs:23:40
47+
|
48+
23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
49+
| ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertSrcIsFromBytes`
50+
= note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
51+
52+
error[E0277]: the trait bound `Dst: FromBytes` is not satisfied
53+
--> tests/ui-nightly/try_transmute_mut-src-not-frombytes.rs:23:40
54+
|
55+
23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
56+
| ^^^^^^^^^^^^^^^^^^^^^^^^
57+
| |
58+
| the trait `FromBytes` is not implemented for `Dst`
59+
| required by a bound introduced by this call
60+
|
61+
= note: Consider adding `#[derive(FromBytes)]` to `Dst`
62+
= help: the following other types implement trait `FromBytes`:
63+
()
64+
AtomicI16
65+
AtomicI32
66+
AtomicI64
67+
AtomicI8
68+
AtomicIsize
69+
AtomicU16
70+
AtomicU32
71+
and $N others
72+
note: required by a bound in `AssertDstIsFromBytes`
73+
--> tests/ui-nightly/try_transmute_mut-src-not-frombytes.rs:23:40
74+
|
75+
23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
76+
| ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsFromBytes`
77+
= note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)
78+
79+
error[E0277]: the trait bound `Dst: IntoBytes` is not satisfied
80+
--> tests/ui-nightly/try_transmute_mut-src-not-frombytes.rs:23:40
81+
|
82+
23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
83+
| ^^^^^^^^^^^^^^^^^^^^^^^^
84+
| |
85+
| the trait `IntoBytes` is not implemented for `Dst`
86+
| required by a bound introduced by this call
87+
|
88+
= note: Consider adding `#[derive(IntoBytes)]` to `Dst`
89+
= help: the following other types implement trait `IntoBytes`:
90+
()
91+
AtomicBool
92+
AtomicI16
93+
AtomicI32
94+
AtomicI64
95+
AtomicI8
96+
AtomicIsize
97+
AtomicU16
98+
and $N others
99+
note: required by a bound in `AssertDstIsIntoBytes`
100+
--> tests/ui-nightly/try_transmute_mut-src-not-frombytes.rs:23:40
101+
|
102+
23 | let src_not_from_bytes: &mut Dst = transmute_mut!(&mut Src);
103+
| ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `AssertDstIsIntoBytes`
104+
= note: this error originates in the macro `transmute_mut` (in Nightly builds, run with -Z macro-backtrace for more info)

tests/ui-nightly/try_transmute_mut-src-not-intobytes.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,19 @@
66
// This file may not be copied, modified, or distributed except according to
77
// those terms.
88

9-
include!("../../zerocopy-derive/tests/include.rs");
10-
119
extern crate zerocopy;
1210

13-
use util::{NotZerocopy, AU16};
14-
use zerocopy::try_transmute_mut;
11+
use zerocopy::transmute_mut;
12+
13+
#[derive(zerocopy::FromBytes)]
14+
#[repr(C)]
15+
struct Src;
16+
17+
#[derive(zerocopy::TryFromBytes)]
18+
#[repr(C)]
19+
struct Dst;
1520

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

0 commit comments

Comments
 (0)