Skip to content

Commit 9f35f36

Browse files
authored
Reduce MSRV to 1.61.0 (#234)
It turned out that there were only a few lines of code that required our MSRV to be as high as it was before this commit (1.65.0), and those lines were easy to modify to be compatible with this new MSRV. Note that this requires introducing defensive code to `FromZeroes::new_box_slice_zeroed` in order to sidestep a bug in `Layout::from_size_align` that was present through 1.64.0.
1 parent 8effca5 commit 9f35f36

12 files changed

+81
-208
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ authors = ["Joshua Liebow-Feeser <[email protected]>"]
1616
description = "Utilities for zero-copy parsing and serialization"
1717
license = "BSD-2-Clause"
1818
repository = "https://github.com/google/zerocopy"
19-
rust-version = "1.65.0"
19+
rust-version = "1.61.0"
2020

2121
exclude = [".*"]
2222

src/lib.rs

Lines changed: 41 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -334,15 +334,23 @@ pub unsafe trait FromZeroes {
334334
where
335335
Self: Sized,
336336
{
337+
let size = mem::size_of::<Self>()
338+
.checked_mul(len)
339+
.expect("mem::size_of::<Self>() * len overflows `usize`");
340+
let align = mem::align_of::<Self>();
341+
// On stable Rust versions <= 1.64.0, `Layout::from_size_align` has a
342+
// bug in which sufficiently-large allocations (those which, when
343+
// rounded up to the alignment, overflow `isize`) are not rejected,
344+
// which can cause undefined behavior. See #64 for details.
345+
//
346+
// TODO(#67): Once our MSRV is > 1.64.0, remove this assertion.
347+
#[allow(clippy::as_conversions)]
348+
let max_alloc = (isize::MAX as usize).saturating_sub(align);
349+
assert!(size <= max_alloc);
337350
// TODO(#2): Use `Layout::repeat` when `alloc_layout_extra` is
338351
// stabilized.
339-
let layout = Layout::from_size_align(
340-
mem::size_of::<Self>()
341-
.checked_mul(len)
342-
.expect("mem::size_of::<Self>() * len overflows `usize`"),
343-
mem::align_of::<Self>(),
344-
)
345-
.expect("total allocation size overflows `isize`");
352+
let layout =
353+
Layout::from_size_align(size, align).expect("total allocation size overflows `isize`");
346354

347355
// TODO(#61): Add a "SAFETY" comment and remove this `allow`.
348356
#[allow(clippy::undocumented_unsafe_blocks)]
@@ -1265,12 +1273,16 @@ impl<T> Unalign<T> {
12651273
/// If `self` does not satisfy `mem::align_of::<T>()`, then
12661274
/// `self.deref_unchecked()` may cause undefined behavior.
12671275
pub const unsafe fn deref_unchecked(&self) -> &T {
1268-
// SAFETY: `self.get_ptr()` returns a raw pointer to a valid `T` at the
1269-
// same memory location as `self`. It has no alignment guarantee, but
1270-
// the caller has promised that `self` is properly aligned, so we know
1271-
// that the pointer itself is aligned, and thus that it is sound to
1272-
// create a reference to a `T` at this memory location.
1273-
unsafe { &*self.get_ptr() }
1276+
// SAFETY: `Unalign<T>` is `repr(transparent)`, so there is a valid `T`
1277+
// at the same memory location as `self`. It has no alignment guarantee,
1278+
// but the caller has promised that `self` is properly aligned, so we
1279+
// know that it is sound to create a reference to `T` at this memory
1280+
// location.
1281+
//
1282+
// We use `mem::transmute` instead of `&*self.get_ptr()` because
1283+
// dereferencing pointers is not stable in `const` on our current MSRV
1284+
// (1.56 as of this writing).
1285+
unsafe { mem::transmute(self) }
12741286
}
12751287

12761288
/// Returns a mutable reference to the wrapped `T` without checking
@@ -1518,6 +1530,10 @@ macro_rules! transmute {
15181530
// were to use `core::mem::transmute`, this macro would not work in
15191531
// `std` contexts in which `core` was not manually imported. This is
15201532
// not a problem for 2018 edition crates.
1533+
//
1534+
// Some older versions of Clippy have a bug in which they don't
1535+
// recognize the preceding safety comment.
1536+
#[allow(clippy::undocumented_unsafe_blocks)]
15211537
unsafe { $crate::__real_transmute(e) }
15221538
}
15231539
}}
@@ -2782,17 +2798,12 @@ mod alloc_support {
27822798

27832799
#[cfg(test)]
27842800
mod tests {
2785-
use core::convert::TryFrom as _;
2786-
27872801
use super::*;
27882802

27892803
#[test]
27902804
fn test_extend_vec_zeroed() {
27912805
// Test extending when there is an existing allocation.
2792-
let mut v: Vec<u64> = Vec::with_capacity(3);
2793-
v.push(100);
2794-
v.push(200);
2795-
v.push(300);
2806+
let mut v = vec![100u64, 200, 300];
27962807
extend_vec_zeroed(&mut v, 3);
27972808
assert_eq!(v.len(), 6);
27982809
assert_eq!(&*v, &[100, 200, 300, 0, 0, 0]);
@@ -2809,10 +2820,7 @@ mod alloc_support {
28092820
#[test]
28102821
fn test_extend_vec_zeroed_zst() {
28112822
// Test extending when there is an existing (fake) allocation.
2812-
let mut v: Vec<()> = Vec::with_capacity(3);
2813-
v.push(());
2814-
v.push(());
2815-
v.push(());
2823+
let mut v = vec![(), (), ()];
28162824
extend_vec_zeroed(&mut v, 3);
28172825
assert_eq!(v.len(), 6);
28182826
assert_eq!(&*v, &[(), (), (), (), (), ()]);
@@ -2835,30 +2843,21 @@ mod alloc_support {
28352843
drop(v);
28362844

28372845
// Insert at start.
2838-
let mut v: Vec<u64> = Vec::with_capacity(3);
2839-
v.push(100);
2840-
v.push(200);
2841-
v.push(300);
2846+
let mut v = vec![100u64, 200, 300];
28422847
insert_vec_zeroed(&mut v, 0, 2);
28432848
assert_eq!(v.len(), 5);
28442849
assert_eq!(&*v, &[0, 0, 100, 200, 300]);
28452850
drop(v);
28462851

28472852
// Insert at middle.
2848-
let mut v: Vec<u64> = Vec::with_capacity(3);
2849-
v.push(100);
2850-
v.push(200);
2851-
v.push(300);
2853+
let mut v = vec![100u64, 200, 300];
28522854
insert_vec_zeroed(&mut v, 1, 1);
28532855
assert_eq!(v.len(), 4);
28542856
assert_eq!(&*v, &[100, 0, 200, 300]);
28552857
drop(v);
28562858

28572859
// Insert at end.
2858-
let mut v: Vec<u64> = Vec::with_capacity(3);
2859-
v.push(100);
2860-
v.push(200);
2861-
v.push(300);
2860+
let mut v = vec![100u64, 200, 300];
28622861
insert_vec_zeroed(&mut v, 3, 1);
28632862
assert_eq!(v.len(), 4);
28642863
assert_eq!(&*v, &[100, 200, 300, 0]);
@@ -2875,30 +2874,21 @@ mod alloc_support {
28752874
drop(v);
28762875

28772876
// Insert at start.
2878-
let mut v: Vec<()> = Vec::with_capacity(3);
2879-
v.push(());
2880-
v.push(());
2881-
v.push(());
2877+
let mut v = vec![(), (), ()];
28822878
insert_vec_zeroed(&mut v, 0, 2);
28832879
assert_eq!(v.len(), 5);
28842880
assert_eq!(&*v, &[(), (), (), (), ()]);
28852881
drop(v);
28862882

28872883
// Insert at middle.
2888-
let mut v: Vec<()> = Vec::with_capacity(3);
2889-
v.push(());
2890-
v.push(());
2891-
v.push(());
2884+
let mut v = vec![(), (), ()];
28922885
insert_vec_zeroed(&mut v, 1, 1);
28932886
assert_eq!(v.len(), 4);
28942887
assert_eq!(&*v, &[(), (), (), ()]);
28952888
drop(v);
28962889

28972890
// Insert at end.
2898-
let mut v: Vec<()> = Vec::with_capacity(3);
2899-
v.push(());
2900-
v.push(());
2901-
v.push(());
2891+
let mut v = vec![(), (), ()];
29022892
insert_vec_zeroed(&mut v, 3, 1);
29032893
assert_eq!(v.len(), 4);
29042894
assert_eq!(&*v, &[(), (), (), ()]);
@@ -2967,7 +2957,7 @@ mod alloc_support {
29672957
}
29682958

29692959
#[test]
2970-
#[should_panic(expected = "total allocation size overflows `isize`: LayoutError")]
2960+
#[should_panic(expected = "assertion failed: size <= max_alloc")]
29712961
fn test_new_box_slice_zeroed_panics_isize_overflow() {
29722962
let max = usize::try_from(isize::MAX).unwrap();
29732963
let _ = u16::new_box_slice_zeroed((max / mem::size_of::<u16>()) + 1);
@@ -3758,7 +3748,7 @@ mod tests {
37583748
/// has had its bits flipped (by applying `^= 0xFF`).
37593749
///
37603750
/// `N` is the size of `t` in bytes.
3761-
fn test<const N: usize, T: FromBytes + AsBytes + Debug + Eq + ?Sized>(
3751+
fn test<T: FromBytes + AsBytes + Debug + Eq + ?Sized, const N: usize>(
37623752
t: &mut T,
37633753
bytes: &[u8],
37643754
post_mutation: &T,
@@ -3830,12 +3820,12 @@ mod tests {
38303820
};
38313821
let post_mutation_expected_a =
38323822
if cfg!(target_endian = "little") { 0x00_00_00_FE } else { 0xFF_00_00_01 };
3833-
test::<12, _>(
3823+
test::<_, 12>(
38343824
&mut Foo { a: 1, b: Wrapping(2), c: None },
38353825
expected_bytes.as_bytes(),
38363826
&Foo { a: post_mutation_expected_a, b: Wrapping(2), c: None },
38373827
);
3838-
test::<3, _>(
3828+
test::<_, 3>(
38393829
Unsized::from_mut_slice(&mut [1, 2, 3]),
38403830
&[1, 2, 3],
38413831
Unsized::from_mut_slice(&mut [0xFE, 2, 3]),

tests/trybuild.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@
1515
// - `tests/ui-msrv` - Contains symlinks to the `.rs` files in
1616
// `tests/ui-nightly`, and contains `.err` and `.out` files for MSRV
1717

18-
#[rustversion::any(nightly)]
18+
#[rustversion::nightly]
1919
const SOURCE_FILES_GLOB: &str = "tests/ui-nightly/*.rs";
20-
#[rustversion::all(stable, not(stable(1.65.0)))]
20+
#[rustversion::stable(1.69.0)]
2121
const SOURCE_FILES_GLOB: &str = "tests/ui-stable/*.rs";
22-
#[rustversion::stable(1.65.0)]
22+
#[rustversion::stable(1.61.0)]
2323
const SOURCE_FILES_GLOB: &str = "tests/ui-msrv/*.rs";
2424

2525
#[test]

tests/ui-msrv/transmute-illegal.stderr

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,13 @@ error[E0277]: the trait bound `*const usize: AsBytes` is not satisfied
22
--> tests/ui-msrv/transmute-illegal.rs:10:30
33
|
44
10 | const POINTER_VALUE: usize = zerocopy::transmute!(&0usize as *const usize);
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6-
| |
7-
| the trait `AsBytes` is not implemented for `*const usize`
8-
| required by a bound introduced by this call
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `AsBytes` is not implemented for `*const usize`
96
|
10-
= help: the following other types implement trait `AsBytes`:
11-
f32
12-
f64
13-
i128
14-
i16
15-
i32
16-
i64
17-
i8
18-
isize
7+
= help: the following implementations were found:
8+
<usize as AsBytes>
9+
<f32 as AsBytes>
10+
<f64 as AsBytes>
11+
<i128 as AsBytes>
1912
and $N others
2013
note: required by a bound in `POINTER_VALUE::transmute`
2114
--> tests/ui-msrv/transmute-illegal.rs:10:30

zerocopy-derive/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ authors = ["Joshua Liebow-Feeser <[email protected]>"]
1010
description = "Custom derive for traits from the zerocopy crate"
1111
license = "BSD-2-Clause"
1212
repository = "https://github.com/google/zerocopy"
13-
rust-version = "1.65.0"
13+
rust-version = "1.61.0"
1414

1515
exclude = [".*"]
1616

zerocopy-derive/src/repr.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ impl Repr {
191191
let ident = path
192192
.get_ident()
193193
.ok_or_else(|| Error::new_spanned(meta, "unrecognized representation hint"))?;
194-
match format!("{ident}").as_str() {
194+
match format!("{}", ident).as_str() {
195195
"u8" => return Ok(Repr::U8),
196196
"u16" => return Ok(Repr::U16),
197197
"u32" => return Ok(Repr::U32),
@@ -221,7 +221,7 @@ impl Repr {
221221
impl Display for Repr {
222222
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
223223
if let Repr::Align(n) = self {
224-
return write!(f, "repr(align({n}))");
224+
return write!(f, "repr(align({}))", n);
225225
}
226226
write!(
227227
f,

zerocopy-derive/tests/trybuild.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@
1515
// - `tests/ui-msrv` - Contains symlinks to the `.rs` files in
1616
// `tests/ui-nightly`, and contains `.err` and `.out` files for MSRV
1717

18-
#[rustversion::any(nightly)]
18+
#[rustversion::nightly]
1919
const SOURCE_FILES_GLOB: &str = "tests/ui-nightly/*.rs";
20-
#[rustversion::all(stable, not(stable(1.65.0)))]
20+
#[rustversion::stable(1.69.0)]
2121
const SOURCE_FILES_GLOB: &str = "tests/ui-stable/*.rs";
22-
#[rustversion::stable(1.65.0)]
22+
#[rustversion::stable(1.61.0)]
2323
const SOURCE_FILES_GLOB: &str = "tests/ui-msrv/*.rs";
2424

2525
#[test]

0 commit comments

Comments
 (0)