From a0bd1a695d20da88668a4549f71e86d0f976de15 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 14 Dec 2019 00:19:24 +0100 Subject: [PATCH] Prevent an ICE on invalid transmutes --- src/librustc/mir/interpret/error.rs | 6 + src/librustc_mir/interpret/place.rs | 10 +- .../transmute-size-mismatch-before-typeck.rs | 15 ++ ...ansmute-size-mismatch-before-typeck.stderr | 136 ++++++++++++++++++ 4 files changed, 161 insertions(+), 6 deletions(-) create mode 100644 src/test/ui/consts/transmute-size-mismatch-before-typeck.rs create mode 100644 src/test/ui/consts/transmute-size-mismatch-before-typeck.stderr diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index 843880200f3..51f0818fe0b 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -432,6 +432,7 @@ pub enum UnsupportedOpInfo<'tcx> { HeapAllocNonPowerOfTwoAlignment(u64), ReadFromReturnPointer, PathNotFound(Vec), + TransmuteSizeDiff(Ty<'tcx>, Ty<'tcx>), } impl fmt::Debug for UnsupportedOpInfo<'tcx> { @@ -460,6 +461,11 @@ impl fmt::Debug for UnsupportedOpInfo<'tcx> { passing data of type {:?}", callee_ty, caller_ty ), + TransmuteSizeDiff(from_ty, to_ty) => write!( + f, + "tried to transmute from {:?} to {:?}, but their sizes differed", + from_ty, to_ty + ), FunctionRetMismatch(caller_ty, callee_ty) => write!( f, "tried to call a function with return type {:?} \ diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index c4607569933..50953348fdc 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -923,12 +923,10 @@ where return self.copy_op(src, dest); } // We still require the sizes to match. - assert!( - src.layout.size == dest.layout.size, - "Size mismatch when transmuting!\nsrc: {:#?}\ndest: {:#?}", - src, - dest - ); + if src.layout.size != dest.layout.size { + error!("Size mismatch when transmuting!\nsrc: {:#?}\ndest: {:#?}", src, dest); + throw_unsup!(TransmuteSizeDiff(src.layout.ty, dest.layout.ty)); + } // Unsized copies rely on interpreting `src.meta` with `dest.layout`, we want // to avoid that here. assert!( diff --git a/src/test/ui/consts/transmute-size-mismatch-before-typeck.rs b/src/test/ui/consts/transmute-size-mismatch-before-typeck.rs new file mode 100644 index 00000000000..1235dd8dcbd --- /dev/null +++ b/src/test/ui/consts/transmute-size-mismatch-before-typeck.rs @@ -0,0 +1,15 @@ +#![feature(const_transmute)] + +fn main() { + match &b""[..] { + ZST => {} + //~^ ERROR could not evaluate constant pattern + } +} + +const ZST: &[u8] = unsafe { std::mem::transmute(1usize) }; +//~^ ERROR any use of this value will cause an error +//~| ERROR cannot transmute between types of different sizes + +// Once the `any use of this value will cause an error` disappears in this test, make sure to +// remove the `TransmuteSizeDiff` error variant and make its emitter site an assertion again. diff --git a/src/test/ui/consts/transmute-size-mismatch-before-typeck.stderr b/src/test/ui/consts/transmute-size-mismatch-before-typeck.stderr new file mode 100644 index 00000000000..29aeb428987 --- /dev/null +++ b/src/test/ui/consts/transmute-size-mismatch-before-typeck.stderr @@ -0,0 +1,136 @@ +[ERROR rustc_mir::interpret::place] Size mismatch when transmuting! + src: OpTy { + op: Immediate( + Scalar( + 0x0000000000000001, + ), + ), + layout: TyLayout { + ty: usize, + details: LayoutDetails { + variants: Single { + index: 0, + }, + fields: Union( + 0, + ), + abi: Scalar( + Scalar { + value: Int( + I64, + false, + ), + valid_range: 0..=18446744073709551615, + }, + ), + largest_niche: None, + align: AbiAndPrefAlign { + abi: Align { + pow2: 3, + }, + pref: Align { + pow2: 3, + }, + }, + size: Size { + raw: 8, + }, + }, + }, + } + dest: PlaceTy { + place: Ptr( + MemPlace { + ptr: AllocId(0).0x0, + align: Align { + pow2: 3, + }, + meta: None, + }, + ), + layout: TyLayout { + ty: &[u8], + details: LayoutDetails { + variants: Single { + index: 0, + }, + fields: Arbitrary { + offsets: [ + Size { + raw: 0, + }, + Size { + raw: 8, + }, + ], + memory_index: [ + 0, + 1, + ], + }, + abi: ScalarPair( + Scalar { + value: Pointer, + valid_range: 1..=18446744073709551615, + }, + Scalar { + value: Int( + I64, + false, + ), + valid_range: 0..=18446744073709551615, + }, + ), + largest_niche: Some( + Niche { + offset: Size { + raw: 0, + }, + scalar: Scalar { + value: Pointer, + valid_range: 1..=18446744073709551615, + }, + }, + ), + align: AbiAndPrefAlign { + abi: Align { + pow2: 3, + }, + pref: Align { + pow2: 3, + }, + }, + size: Size { + raw: 16, + }, + }, + }, + } +error: any use of this value will cause an error + --> $DIR/transmute-size-mismatch-before-typeck.rs:10:29 + | +LL | const ZST: &[u8] = unsafe { std::mem::transmute(1usize) }; + | ----------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^--- + | | + | tried to transmute from usize to &[u8], but their sizes differed + | + = note: `#[deny(const_err)]` on by default + +error: could not evaluate constant pattern + --> $DIR/transmute-size-mismatch-before-typeck.rs:5:9 + | +LL | ZST => {} + | ^^^ + +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> $DIR/transmute-size-mismatch-before-typeck.rs:10:29 + | +LL | const ZST: &[u8] = unsafe { std::mem::transmute(1usize) }; + | ^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `usize` (64 bits) + = note: target type: `&'static [u8]` (128 bits) + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0512`.