miri: restrict fn argument punning to Rust ABI

This commit is contained in:
Ralf Jung 2018-11-22 17:38:59 +01:00
parent e1ca4f63f4
commit d9de72fcac

View File

@ -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<Item=OpTy<'tcx, M::PointerTag>>,
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
));