when Miri calls a function ptr, make sure it has the right ABI

This commit is contained in:
Ralf Jung 2021-03-14 15:30:37 +01:00
parent ae964207bb
commit 893843fd45
7 changed files with 24 additions and 1 deletions

View File

@ -8,6 +8,7 @@ use log::info;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::{self, layout::LayoutCx, TyCtxt};
use rustc_target::abi::LayoutOf;
use rustc_target::spec::abi::Abi;
use crate::*;
@ -189,6 +190,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
// Call start function.
ecx.call_function(
start_instance,
Abi::Rust,
&[main_ptr.into(), argc.into(), argv.into()],
Some(&ret_place.into()),
StackPopCleanup::None { cleanup: true },

View File

@ -161,11 +161,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
fn call_function(
&mut self,
f: ty::Instance<'tcx>,
caller_abi: Abi,
args: &[Immediate<Tag>],
dest: Option<&PlaceTy<'tcx, Tag>>,
stack_pop: StackPopCleanup,
) -> InterpResult<'tcx> {
let this = self.eval_context_mut();
let param_env = ty::ParamEnv::reveal_all(); // in Miri this is always the param_env we use... and this.param_env is private.
let callee_abi = f.ty(*this.tcx, param_env).fn_sig(*this.tcx).abi();
if callee_abi != caller_abi {
throw_ub_format!("calling a function with ABI {} using caller ABI {}", callee_abi.name(), caller_abi.name())
}
// Push frame.
let mir = &*this.load_mir(f.def, None)?;

View File

@ -430,6 +430,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> {
let malloc = ty::Instance::mono(ecx.tcx.tcx, malloc);
ecx.call_function(
malloc,
Abi::Rust,
&[size.into(), align.into()],
Some(dest),
// Don't do anything when we are done. The `statement()` function will increment

View File

@ -15,6 +15,7 @@ use log::trace;
use rustc_middle::{mir, ty};
use rustc_target::spec::PanicStrategy;
use rustc_target::spec::abi::Abi;
use crate::*;
use helpers::check_arg_count;
@ -94,6 +95,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into();
this.call_function(
f_instance,
Abi::Rust,
&[data.into()],
Some(&ret_place),
// Directly return to caller.
@ -145,6 +147,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into();
this.call_function(
f_instance,
Abi::Rust,
&[catch_unwind.data.into(), payload.into()],
Some(&ret_place),
// Directly return to caller of `try`.
@ -174,6 +177,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
let panic = ty::Instance::mono(this.tcx.tcx, panic);
this.call_function(
panic,
Abi::Rust,
&[msg.to_ref()],
None,
StackPopCleanup::Goto { ret: None, unwind },
@ -202,6 +206,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
let panic_bounds_check = ty::Instance::mono(this.tcx.tcx, panic_bounds_check);
this.call_function(
panic_bounds_check,
Abi::Rust,
&[index.into(), len.into()],
None,
StackPopCleanup::Goto { ret: None, unwind },

View File

@ -2,6 +2,7 @@ use std::convert::TryInto;
use crate::*;
use rustc_target::abi::LayoutOf;
use rustc_target::spec::abi::Abi;
impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
@ -50,6 +51,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
this.call_function(
instance,
Abi::C { unwind: false },
&[*func_arg],
Some(&ret_place.into()),
StackPopCleanup::None { cleanup: true },

View File

@ -9,6 +9,7 @@ use log::trace;
use rustc_data_structures::fx::FxHashMap;
use rustc_middle::ty;
use rustc_target::abi::{Size, HasDataLayout};
use rustc_target::spec::abi::Abi;
use crate::*;
@ -244,6 +245,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into();
this.call_function(
thread_callback,
Abi::System { unwind: false },
&[Scalar::null_ptr(this).into(), reason.into(), Scalar::null_ptr(this).into()],
Some(&ret_place),
StackPopCleanup::None { cleanup: true },
@ -266,6 +268,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into();
this.call_function(
instance,
Abi::C { unwind: false },
&[data.into()],
Some(&ret_place),
StackPopCleanup::None { cleanup: true },
@ -306,6 +309,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into();
this.call_function(
instance,
Abi::C { unwind: false },
&[ptr.into()],
Some(&ret_place),
StackPopCleanup::None { cleanup: true },

View File

@ -1,7 +1,10 @@
// ignore-windows: Concurrency on Windows is not supported yet.
// error-pattern: unwinding past the topmost frame of the stack
// error-pattern: calling a function with ABI C-unwind using caller ABI C
//! Unwinding past the top frame of a stack is Undefined Behavior.
//! However, it is impossible to do that in pure Rust since one cannot write an unwinding
//! function with `C` ABI... so let's instead test that we are indeed correctly checking
//! the callee ABI in `pthread_create`.
#![feature(rustc_private, c_unwind)]