Skip to content

Commit 4103c54

Browse files
authored
Merge pull request #4497 from RalfJung/check-shim
introduce a macro for shim signature checking
2 parents 812d9ad + 20714f7 commit 4103c54

37 files changed

+897
-793
lines changed

src/tools/miri/src/helpers.rs

Lines changed: 2 additions & 206 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

@@ -930,21 +929,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
930929
self.read_c_str_with_char_size(ptr, wchar_t.size, wchar_t.align.abi)
931930
}
932931

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

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

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

src/tools/miri/src/shims/backtrace.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
1515
dest: &MPlaceTy<'tcx>,
1616
) -> InterpResult<'tcx> {
1717
let this = self.eval_context_mut();
18-
let [flags] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
18+
let [flags] = this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?;
1919

2020
let flags = this.read_scalar(flags)?.to_u64()?;
2121
if flags != 0 {
@@ -37,7 +37,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
3737
let ptr_ty = this.machine.layouts.mut_raw_ptr.ty;
3838
let ptr_layout = this.layout_of(ptr_ty)?;
3939

40-
let [flags, buf] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
40+
let [flags, buf] = this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?;
4141

4242
let flags = this.read_scalar(flags)?.to_u64()?;
4343
let buf_place = this.deref_pointer_as(buf, ptr_layout)?;
@@ -117,7 +117,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
117117
dest: &MPlaceTy<'tcx>,
118118
) -> InterpResult<'tcx> {
119119
let this = self.eval_context_mut();
120-
let [ptr, flags] = this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
120+
let [ptr, flags] = this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?;
121121

122122
let flags = this.read_scalar(flags)?.to_u64()?;
123123

@@ -195,7 +195,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
195195
let this = self.eval_context_mut();
196196

197197
let [ptr, flags, name_ptr, filename_ptr] =
198-
this.check_shim(abi, CanonAbi::Rust, link_name, args)?;
198+
this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?;
199199

200200
let flags = this.read_scalar(flags)?.to_u64()?;
201201
if flags != 0 {

0 commit comments

Comments
 (0)