From d9de72fcac7cfd90742a8fa8e4f6c0efd664ecde Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 22 Nov 2018 17:38:59 +0100 Subject: [PATCH] miri: restrict fn argument punning to Rust ABI --- src/librustc_mir/interpret/terminator.rs | 33 +++++++++++++++--------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs index 4489465679740..11c44fc943daa 100644 --- a/src/librustc_mir/interpret/terminator.rs +++ b/src/librustc_mir/interpret/terminator.rs @@ -182,6 +182,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> } fn check_argument_compat( + rust_abi: bool, caller: TyLayout<'tcx>, callee: TyLayout<'tcx>, ) -> bool { @@ -189,12 +190,16 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> // No question return true; } + if !rust_abi { + // Don't risk anything + return false; + } // Compare layout match (&caller.abi, &callee.abi) { + // Different valid ranges are okay (once we enforce validity, + // that will take care to make it UB to leave the range, just + // like for transmute). (layout::Abi::Scalar(ref caller), layout::Abi::Scalar(ref callee)) => - // Different valid ranges are okay (once we enforce validity, - // that will take care to make it UB to leave the range, just - // like for transmute). caller.value == callee.value, (layout::Abi::ScalarPair(ref caller1, ref caller2), layout::Abi::ScalarPair(ref callee1, ref callee2)) => @@ -207,22 +212,22 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> /// Pass a single argument, checking the types for compatibility. fn pass_argument( &mut self, - skip_zst: bool, + rust_abi: bool, caller_arg: &mut impl Iterator>, callee_arg: PlaceTy<'tcx, M::PointerTag>, ) -> EvalResult<'tcx> { - if skip_zst && callee_arg.layout.is_zst() { + if rust_abi && callee_arg.layout.is_zst() { // Nothing to do. trace!("Skipping callee ZST"); return Ok(()); } let caller_arg = caller_arg.next() .ok_or_else(|| EvalErrorKind::FunctionArgCountMismatch)?; - if skip_zst { + if rust_abi { debug_assert!(!caller_arg.layout.is_zst(), "ZSTs must have been already filtered out"); } // Now, check - if !Self::check_argument_compat(caller_arg.layout, callee_arg.layout) { + if !Self::check_argument_compat(rust_abi, caller_arg.layout, callee_arg.layout) { return err!(FunctionArgMismatch(caller_arg.layout.ty, callee_arg.layout.ty)); } // We allow some transmutes here @@ -322,7 +327,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> // Figure out how to pass which arguments. // We have two iterators: Where the arguments come from, // and where they go to. - let skip_zst = match caller_abi { + let rust_abi = match caller_abi { Abi::Rust | Abi::RustCall => true, _ => false }; @@ -347,7 +352,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> }; // Skip ZSTs let mut caller_iter = caller_args.iter() - .filter(|op| !skip_zst || !op.layout.is_zst()) + .filter(|op| !rust_abi || !op.layout.is_zst()) .map(|op| *op); // Now we have to spread them out across the callee's locals, @@ -362,11 +367,11 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> // Must be a tuple for i in 0..dest.layout.fields.count() { let dest = self.place_field(dest, i as u64)?; - self.pass_argument(skip_zst, &mut caller_iter, dest)?; + self.pass_argument(rust_abi, &mut caller_iter, dest)?; } } else { // Normal argument - self.pass_argument(skip_zst, &mut caller_iter, dest)?; + self.pass_argument(rust_abi, &mut caller_iter, dest)?; } } // Now we should have no more caller args @@ -377,7 +382,11 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> // Don't forget to check the return type! if let Some(caller_ret) = dest { let callee_ret = self.eval_place(&mir::Place::Local(mir::RETURN_PLACE))?; - if !Self::check_argument_compat(caller_ret.layout, callee_ret.layout) { + if !Self::check_argument_compat( + rust_abi, + caller_ret.layout, + callee_ret.layout, + ) { return err!(FunctionRetMismatch( caller_ret.layout.ty, callee_ret.layout.ty ));