Skip to content

Commit 20714f7

Browse files
introduce a macro for shim signature checking
Co-Authored-By: geetanshjuneja <[email protected]>
1 parent 94ce66d commit 20714f7

37 files changed

+900
-795
lines changed

src/tools/miri/src/helpers.rs

Lines changed: 5 additions & 208 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::time::Duration;
33
use std::{cmp, iter};
44

55
use rand::RngCore;
6-
use rustc_abi::{Align, CanonAbi, ExternAbi, FieldIdx, FieldsShape, Size, Variants};
6+
use rustc_abi::{Align, ExternAbi, FieldIdx, FieldsShape, Size, Variants};
77
use rustc_apfloat::Float;
88
use rustc_apfloat::ieee::{Double, Half, Quad, Single};
99
use rustc_hir::Safety;
@@ -14,11 +14,10 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
1414
use rustc_middle::middle::dependency_format::Linkage;
1515
use rustc_middle::middle::exported_symbols::ExportedSymbol;
1616
use rustc_middle::ty::layout::{LayoutOf, MaybeResult, TyAndLayout};
17-
use rustc_middle::ty::{self, Binder, FloatTy, FnSig, IntTy, Ty, TyCtxt, UintTy};
17+
use rustc_middle::ty::{self, FloatTy, IntTy, Ty, TyCtxt, UintTy};
1818
use rustc_session::config::CrateType;
1919
use rustc_span::{Span, Symbol};
2020
use rustc_symbol_mangling::mangle_internal_symbol;
21-
use rustc_target::callconv::FnAbi;
2221

2322
use crate::*;
2423

@@ -437,7 +436,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
437436
/// For now, arguments must be scalars (so that the caller does not have to know the layout).
438437
///
439438
/// If you do not provide a return place, a dangling zero-sized place will be created
440-
/// for your convenience.
439+
/// for your convenience. This is only valid if the return type is `()`.
441440
fn call_function(
442441
&mut self,
443442
f: ty::Instance<'tcx>,
@@ -452,7 +451,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
452451
let mir = this.load_mir(f.def, None)?;
453452
let dest = match dest {
454453
Some(dest) => dest.clone(),
455-
None => MPlaceTy::fake_alloc_zst(this.layout_of(mir.return_ty())?),
454+
None => MPlaceTy::fake_alloc_zst(this.machine.layouts.unit),
456455
};
457456

458457
// Construct a function pointer type representing the caller perspective.
@@ -465,6 +464,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
465464
);
466465
let caller_fn_abi = this.fn_abi_of_fn_ptr(ty::Binder::dummy(sig), ty::List::empty())?;
467466

467+
// This will also show proper errors if there is any ABI mismatch.
468468
this.init_stack_frame(
469469
f,
470470
mir,
@@ -929,21 +929,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
929929
self.read_c_str_with_char_size(ptr, wchar_t.size, wchar_t.align.abi)
930930
}
931931

932-
/// Check that the calling convention is what we expect.
933-
fn check_callconv<'a>(
934-
&self,
935-
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
936-
exp_abi: CanonAbi,
937-
) -> InterpResult<'a, ()> {
938-
if fn_abi.conv != exp_abi {
939-
throw_ub_format!(
940-
r#"calling a function with calling convention "{exp_abi}" using caller calling convention "{}""#,
941-
fn_abi.conv
942-
);
943-
}
944-
interp_ok(())
945-
}
946-
947932
fn frame_in_std(&self) -> bool {
948933
let this = self.eval_context_ref();
949934
let frame = this.frame();
@@ -967,161 +952,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
967952
crate_name == "std" || crate_name == "std_miri_test"
968953
}
969954

970-
fn check_abi_and_shim_symbol_clash(
971-
&mut self,
972-
abi: &FnAbi<'tcx, Ty<'tcx>>,
973-
exp_abi: CanonAbi,
974-
link_name: Symbol,
975-
) -> InterpResult<'tcx, ()> {
976-
self.check_callconv(abi, exp_abi)?;
977-
if let Some((body, instance)) = self.eval_context_mut().lookup_exported_symbol(link_name)? {
978-
// If compiler-builtins is providing the symbol, then don't treat it as a clash.
979-
// We'll use our built-in implementation in `emulate_foreign_item_inner` for increased
980-
// performance. Note that this means we won't catch any undefined behavior in
981-
// compiler-builtins when running other crates, but Miri can still be run on
982-
// compiler-builtins itself (or any crate that uses it as a normal dependency)
983-
if self.eval_context_ref().tcx.is_compiler_builtins(instance.def_id().krate) {
984-
return interp_ok(());
985-
}
986-
987-
throw_machine_stop!(TerminationInfo::SymbolShimClashing {
988-
link_name,
989-
span: body.span.data(),
990-
})
991-
}
992-
interp_ok(())
993-
}
994-
995-
fn check_shim<'a, const N: usize>(
996-
&mut self,
997-
abi: &FnAbi<'tcx, Ty<'tcx>>,
998-
exp_abi: CanonAbi,
999-
link_name: Symbol,
1000-
args: &'a [OpTy<'tcx>],
1001-
) -> InterpResult<'tcx, &'a [OpTy<'tcx>; N]> {
1002-
self.check_abi_and_shim_symbol_clash(abi, exp_abi, link_name)?;
1003-
1004-
if abi.c_variadic {
1005-
throw_ub_format!(
1006-
"calling a non-variadic function with a variadic caller-side signature"
1007-
);
1008-
}
1009-
if let Ok(ops) = args.try_into() {
1010-
return interp_ok(ops);
1011-
}
1012-
throw_ub_format!(
1013-
"incorrect number of arguments for `{link_name}`: got {}, expected {}",
1014-
args.len(),
1015-
N
1016-
)
1017-
}
1018-
1019-
/// Check that the given `caller_fn_abi` matches the expected ABI described by
1020-
/// `callee_abi`, `callee_input_tys`, `callee_output_ty`, and then returns the list of
1021-
/// arguments.
1022-
fn check_shim_abi<'a, const N: usize>(
1023-
&mut self,
1024-
link_name: Symbol,
1025-
caller_fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
1026-
callee_abi: ExternAbi,
1027-
callee_input_tys: [Ty<'tcx>; N],
1028-
callee_output_ty: Ty<'tcx>,
1029-
caller_args: &'a [OpTy<'tcx>],
1030-
) -> InterpResult<'tcx, &'a [OpTy<'tcx>; N]> {
1031-
let this = self.eval_context_mut();
1032-
let mut inputs_and_output = callee_input_tys.to_vec();
1033-
inputs_and_output.push(callee_output_ty);
1034-
let fn_sig_binder = Binder::dummy(FnSig {
1035-
inputs_and_output: this.machine.tcx.mk_type_list(&inputs_and_output),
1036-
c_variadic: false,
1037-
// This does not matter for the ABI.
1038-
safety: Safety::Safe,
1039-
abi: callee_abi,
1040-
});
1041-
let callee_fn_abi = this.fn_abi_of_fn_ptr(fn_sig_binder, Default::default())?;
1042-
1043-
this.check_abi_and_shim_symbol_clash(caller_fn_abi, callee_fn_abi.conv, link_name)?;
1044-
1045-
if caller_fn_abi.c_variadic {
1046-
throw_ub_format!(
1047-
"ABI mismatch: calling a non-variadic function with a variadic caller-side signature"
1048-
);
1049-
}
1050-
1051-
if callee_fn_abi.fixed_count != caller_fn_abi.fixed_count {
1052-
throw_ub_format!(
1053-
"ABI mismatch: expected {} arguments, found {} arguments ",
1054-
callee_fn_abi.fixed_count,
1055-
caller_fn_abi.fixed_count
1056-
);
1057-
}
1058-
1059-
if callee_fn_abi.can_unwind && !caller_fn_abi.can_unwind {
1060-
throw_ub_format!(
1061-
"ABI mismatch: callee may unwind, but caller-side signature prohibits unwinding",
1062-
);
1063-
}
1064-
1065-
if !this.check_argument_compat(&caller_fn_abi.ret, &callee_fn_abi.ret)? {
1066-
throw_ub!(AbiMismatchReturn {
1067-
caller_ty: caller_fn_abi.ret.layout.ty,
1068-
callee_ty: callee_fn_abi.ret.layout.ty
1069-
});
1070-
}
1071-
1072-
if let Some(index) = caller_fn_abi
1073-
.args
1074-
.iter()
1075-
.zip(callee_fn_abi.args.iter())
1076-
.map(|(caller_arg, callee_arg)| this.check_argument_compat(caller_arg, callee_arg))
1077-
.collect::<InterpResult<'tcx, Vec<bool>>>()?
1078-
.into_iter()
1079-
.position(|b| !b)
1080-
{
1081-
throw_ub!(AbiMismatchArgument {
1082-
caller_ty: caller_fn_abi.args[index].layout.ty,
1083-
callee_ty: callee_fn_abi.args[index].layout.ty
1084-
});
1085-
}
1086-
1087-
if let Ok(ops) = caller_args.try_into() {
1088-
return interp_ok(ops);
1089-
}
1090-
unreachable!()
1091-
}
1092-
1093-
/// Check shim for variadic function.
1094-
/// Returns a tuple that consisting of an array of fixed args, and a slice of varargs.
1095-
fn check_shim_variadic<'a, const N: usize>(
1096-
&mut self,
1097-
abi: &FnAbi<'tcx, Ty<'tcx>>,
1098-
exp_abi: CanonAbi,
1099-
link_name: Symbol,
1100-
args: &'a [OpTy<'tcx>],
1101-
) -> InterpResult<'tcx, (&'a [OpTy<'tcx>; N], &'a [OpTy<'tcx>])>
1102-
where
1103-
&'a [OpTy<'tcx>; N]: TryFrom<&'a [OpTy<'tcx>]>,
1104-
{
1105-
self.check_abi_and_shim_symbol_clash(abi, exp_abi, link_name)?;
1106-
1107-
if !abi.c_variadic {
1108-
throw_ub_format!(
1109-
"calling a variadic function with a non-variadic caller-side signature"
1110-
);
1111-
}
1112-
if abi.fixed_count != u32::try_from(N).unwrap() {
1113-
throw_ub_format!(
1114-
"incorrect number of fixed arguments for variadic function `{}`: got {}, expected {N}",
1115-
link_name.as_str(),
1116-
abi.fixed_count
1117-
)
1118-
}
1119-
if let Some(args) = args.split_first_chunk() {
1120-
return interp_ok(args);
1121-
}
1122-
panic!("mismatch between signature and `args` slice");
1123-
}
1124-
1125955
/// Mark a machine allocation that was just created as immutable.
1126956
fn mark_immutable(&mut self, mplace: &MPlaceTy<'tcx>) {
1127957
let this = self.eval_context_mut();
@@ -1317,39 +1147,6 @@ impl<'tcx> MiriMachine<'tcx> {
13171147
}
13181148
}
13191149

1320-
/// Check that the number of args is what we expect.
1321-
pub fn check_intrinsic_arg_count<'a, 'tcx, const N: usize>(
1322-
args: &'a [OpTy<'tcx>],
1323-
) -> InterpResult<'tcx, &'a [OpTy<'tcx>; N]>
1324-
where
1325-
&'a [OpTy<'tcx>; N]: TryFrom<&'a [OpTy<'tcx>]>,
1326-
{
1327-
if let Ok(ops) = args.try_into() {
1328-
return interp_ok(ops);
1329-
}
1330-
throw_ub_format!(
1331-
"incorrect number of arguments for intrinsic: got {}, expected {}",
1332-
args.len(),
1333-
N
1334-
)
1335-
}
1336-
1337-
/// Check that the number of varargs is at least the minimum what we expect.
1338-
/// Fixed args should not be included.
1339-
pub fn check_min_vararg_count<'a, 'tcx, const N: usize>(
1340-
name: &'a str,
1341-
args: &'a [OpTy<'tcx>],
1342-
) -> InterpResult<'tcx, &'a [OpTy<'tcx>; N]> {
1343-
if let Some((ops, _)) = args.split_first_chunk() {
1344-
return interp_ok(ops);
1345-
}
1346-
throw_ub_format!(
1347-
"not enough variadic arguments for `{name}`: got {}, expected at least {}",
1348-
args.len(),
1349-
N
1350-
)
1351-
}
1352-
13531150
pub fn isolation_abort_error<'tcx>(name: &str) -> InterpResult<'tcx> {
13541151
throw_machine_stop!(TerminationInfo::UnsupportedInIsolation(format!(
13551152
"{name} not available when isolation is enabled",

src/tools/miri/src/intrinsics/atomic.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use rustc_middle::mir::BinOp;
22
use rustc_middle::ty::AtomicOrdering;
33
use rustc_middle::{mir, ty};
44

5-
use self::helpers::check_intrinsic_arg_count;
5+
use super::check_intrinsic_arg_count;
66
use crate::*;
77

88
pub enum AtomicOp {

src/tools/miri/src/intrinsics/mod.rs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,28 @@ use rustc_middle::ty::{self, FloatTy, ScalarInt};
1414
use rustc_span::{Symbol, sym};
1515

1616
use self::atomic::EvalContextExt as _;
17-
use self::helpers::{ToHost, ToSoft, check_intrinsic_arg_count};
17+
use self::helpers::{ToHost, ToSoft};
1818
use self::simd::EvalContextExt as _;
1919
use crate::math::{IeeeExt, apply_random_float_error_ulp};
2020
use crate::*;
2121

22+
/// Check that the number of args is what we expect.
23+
fn check_intrinsic_arg_count<'a, 'tcx, const N: usize>(
24+
args: &'a [OpTy<'tcx>],
25+
) -> InterpResult<'tcx, &'a [OpTy<'tcx>; N]>
26+
where
27+
&'a [OpTy<'tcx>; N]: TryFrom<&'a [OpTy<'tcx>]>,
28+
{
29+
if let Ok(ops) = args.try_into() {
30+
return interp_ok(ops);
31+
}
32+
throw_ub_format!(
33+
"incorrect number of arguments for intrinsic: got {}, expected {}",
34+
args.len(),
35+
N
36+
)
37+
}
38+
2239
impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
2340
pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
2441
fn call_intrinsic(
@@ -114,7 +131,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
114131
));
115132
}
116133
"catch_unwind" => {
117-
this.handle_catch_unwind(args, dest, ret)?;
134+
let [try_fn, data, catch_fn] = check_intrinsic_arg_count(args)?;
135+
this.handle_catch_unwind(try_fn, data, catch_fn, dest, ret)?;
118136
// This pushed a stack frame, don't jump to `ret`.
119137
return interp_ok(EmulateItemResult::AlreadyJumped);
120138
}

src/tools/miri/src/intrinsics/simd.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,8 @@ use rustc_middle::ty::FloatTy;
66
use rustc_middle::{mir, ty};
77
use rustc_span::{Symbol, sym};
88

9-
use crate::helpers::{
10-
ToHost, ToSoft, bool_to_simd_element, check_intrinsic_arg_count, simd_element_to_bool,
11-
};
9+
use super::check_intrinsic_arg_count;
10+
use crate::helpers::{ToHost, ToSoft, bool_to_simd_element, simd_element_to_bool};
1211
use crate::*;
1312

1413
#[derive(Copy, Clone)]

src/tools/miri/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#![feature(never_type)]
88
#![feature(try_blocks)]
99
#![feature(io_error_more)]
10+
#![feature(if_let_guard)]
1011
#![feature(variant_count)]
1112
#![feature(yeet_expr)]
1213
#![feature(nonzero_ops)]
@@ -158,6 +159,7 @@ pub use crate::shims::foreign_items::{DynSym, EvalContextExt as _};
158159
pub use crate::shims::io_error::{EvalContextExt as _, IoError, LibcError};
159160
pub use crate::shims::os_str::EvalContextExt as _;
160161
pub use crate::shims::panic::EvalContextExt as _;
162+
pub use crate::shims::sig::EvalContextExt as _;
161163
pub use crate::shims::time::EvalContextExt as _;
162164
pub use crate::shims::tls::TlsData;
163165
pub use crate::shims::unwind::{CatchUnwindData, EvalContextExt as _};

src/tools/miri/src/shims/aarch64.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
2020
let unprefixed_name = link_name.as_str().strip_prefix("llvm.aarch64.").unwrap();
2121
match unprefixed_name {
2222
"isb" => {
23-
let [arg] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
23+
let [arg] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
2424
let arg = this.read_scalar(arg)?.to_i32()?;
2525
match arg {
2626
// SY ("full system scope")
@@ -38,7 +38,8 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
3838
// `left` input, the second half of the output from the `right` input.
3939
// https://developer.arm.com/architectures/instruction-sets/intrinsics/vpmaxq_u8
4040
"neon.umaxp.v16i8" => {
41-
let [left, right] = this.check_shim(abi, CanonAbi::C, link_name, args)?;
41+
let [left, right] =
42+
this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
4243

4344
let (left, left_len) = this.project_to_simd(left)?;
4445
let (right, right_len) = this.project_to_simd(right)?;

0 commit comments

Comments
 (0)