mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-14 02:49:40 +00:00
miri: restrict fn argument punning to Rust ABI
This commit is contained in:
parent
e1ca4f63f4
commit
d9de72fcac
@ -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
|
||||
));
|
||||
|
Loading…
Reference in New Issue
Block a user