Skip to content

Commit 3d01217

Browse files
authored
Merge pull request #4185 from geetanshjuneja/abi_check
FnAbi Compatability check
2 parents a004c12 + 82dfa03 commit 3d01217

File tree

6 files changed

+161
-7
lines changed

6 files changed

+161
-7
lines changed

src/tools/miri/src/helpers.rs

+76-5
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ 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::{FnAbiOf, LayoutOf, MaybeResult, TyAndLayout};
17-
use rustc_middle::ty::{self, FloatTy, IntTy, Ty, TyCtxt, UintTy};
17+
use rustc_middle::ty::{self, Binder, FloatTy, FnSig, IntTy, Ty, TyCtxt, UintTy};
1818
use rustc_session::config::CrateType;
1919
use rustc_span::{Span, Symbol};
2020
use rustc_target::callconv::{Conv, FnAbi};
@@ -994,10 +994,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
994994
exp_abi: Conv,
995995
link_name: Symbol,
996996
args: &'a [OpTy<'tcx>],
997-
) -> InterpResult<'tcx, &'a [OpTy<'tcx>; N]>
998-
where
999-
&'a [OpTy<'tcx>; N]: TryFrom<&'a [OpTy<'tcx>]>,
1000-
{
997+
) -> InterpResult<'tcx, &'a [OpTy<'tcx>; N]> {
1001998
self.check_abi_and_shim_symbol_clash(abi, exp_abi, link_name)?;
1002999

10031000
if abi.c_variadic {
@@ -1015,6 +1012,80 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
10151012
)
10161013
}
10171014

1015+
/// Check that the given `caller_fn_abi` matches the expected ABI described by
1016+
/// `callee_abi`, `callee_input_tys`, `callee_output_ty`, and the return the list of
1017+
/// arguments.
1018+
fn check_shim_abi<'a, const N: usize>(
1019+
&mut self,
1020+
link_name: Symbol,
1021+
caller_fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
1022+
callee_abi: ExternAbi,
1023+
callee_input_tys: [Ty<'tcx>; N],
1024+
callee_output_ty: Ty<'tcx>,
1025+
caller_args: &'a [OpTy<'tcx>],
1026+
) -> InterpResult<'tcx, &'a [OpTy<'tcx>; N]> {
1027+
let this = self.eval_context_mut();
1028+
let mut inputs_and_output = callee_input_tys.to_vec();
1029+
inputs_and_output.push(callee_output_ty);
1030+
let fn_sig_binder = Binder::dummy(FnSig {
1031+
inputs_and_output: this.machine.tcx.mk_type_list(&inputs_and_output),
1032+
c_variadic: false,
1033+
// This does not matter for the ABI.
1034+
safety: Safety::Safe,
1035+
abi: callee_abi,
1036+
});
1037+
let callee_fn_abi = this.fn_abi_of_fn_ptr(fn_sig_binder, Default::default())?;
1038+
1039+
this.check_abi_and_shim_symbol_clash(caller_fn_abi, callee_fn_abi.conv, link_name)?;
1040+
1041+
if caller_fn_abi.c_variadic {
1042+
throw_ub_format!(
1043+
"ABI mismatch: calling a non-variadic function with a variadic caller-side signature"
1044+
);
1045+
}
1046+
1047+
if callee_fn_abi.fixed_count != caller_fn_abi.fixed_count {
1048+
throw_ub_format!(
1049+
"ABI mismatch: expected {} arguments, found {} arguments ",
1050+
callee_fn_abi.fixed_count,
1051+
caller_fn_abi.fixed_count
1052+
);
1053+
}
1054+
1055+
if callee_fn_abi.can_unwind && !caller_fn_abi.can_unwind {
1056+
throw_ub_format!(
1057+
"ABI mismatch: callee may unwind, but caller-side signature prohibits unwinding",
1058+
);
1059+
}
1060+
1061+
if !this.check_argument_compat(&caller_fn_abi.ret, &callee_fn_abi.ret)? {
1062+
throw_ub!(AbiMismatchReturn {
1063+
caller_ty: caller_fn_abi.ret.layout.ty,
1064+
callee_ty: callee_fn_abi.ret.layout.ty
1065+
});
1066+
}
1067+
1068+
if let Some(index) = caller_fn_abi
1069+
.args
1070+
.iter()
1071+
.zip(callee_fn_abi.args.iter())
1072+
.map(|(caller_arg, callee_arg)| this.check_argument_compat(caller_arg, callee_arg))
1073+
.collect::<InterpResult<'tcx, Vec<bool>>>()?
1074+
.into_iter()
1075+
.position(|b| !b)
1076+
{
1077+
throw_ub!(AbiMismatchArgument {
1078+
caller_ty: caller_fn_abi.args[index].layout.ty,
1079+
callee_ty: callee_fn_abi.args[index].layout.ty
1080+
});
1081+
}
1082+
1083+
if let Ok(ops) = caller_args.try_into() {
1084+
return interp_ok(ops);
1085+
}
1086+
unreachable!()
1087+
}
1088+
10181089
/// Check shim for variadic function.
10191090
/// Returns a tuple that consisting of an array of fixed args, and a slice of varargs.
10201091
fn check_shim_variadic<'a, const N: usize>(

src/tools/miri/src/shims/unix/foreign_items.rs

+9-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::ffi::OsStr;
22
use std::str;
33

4-
use rustc_abi::Size;
4+
use rustc_abi::{ExternAbi, Size};
55
use rustc_middle::ty::Ty;
66
use rustc_middle::ty::layout::LayoutOf;
77
use rustc_span::Symbol;
@@ -200,7 +200,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
200200
this.write(fd, buf, count, Some(offset), dest)?;
201201
}
202202
"close" => {
203-
let [fd] = this.check_shim(abi, Conv::C, link_name, args)?;
203+
let [fd] = this.check_shim_abi(
204+
link_name,
205+
abi,
206+
ExternAbi::C { unwind: false },
207+
[this.tcx.types.i32],
208+
this.tcx.types.i32,
209+
args,
210+
)?;
204211
let result = this.close(fd)?;
205212
this.write_scalar(result, dest)?;
206213
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//@ignore-target: windows # File handling is not implemented yet
2+
//@compile-flags: -Zmiri-disable-isolation
3+
use std::ffi::{CString, OsStr, c_char, c_int};
4+
use std::os::unix::ffi::OsStrExt;
5+
6+
extern "C" {
7+
fn open(path: *const c_char, oflag: c_int, ...) -> c_int;
8+
// correct fd type is i32
9+
fn close(fd: u32) -> c_int;
10+
}
11+
12+
fn main() {
13+
let c_path = CString::new(OsStr::new("./text").as_bytes()).expect("CString::new failed");
14+
let fd = unsafe {
15+
open(c_path.as_ptr(), /* value does not matter */ 0)
16+
} as u32;
17+
let _ = unsafe {
18+
close(fd);
19+
//~^ ERROR: calling a function with argument of type i32 passing data of type u32
20+
};
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
error: Undefined Behavior: calling a function with argument of type i32 passing data of type u32
2+
--> tests/fail/shims/input_arg_mismatch.rs:LL:CC
3+
|
4+
LL | close(fd);
5+
| ^^^^^^^^^ calling a function with argument of type i32 passing data of type u32
6+
|
7+
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
8+
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
9+
= help: this means these two types are not *guaranteed* to be ABI-compatible across all targets
10+
= help: if you think this code should be accepted anyway, please report an issue with Miri
11+
= note: BACKTRACE:
12+
= note: inside `main` at tests/fail/shims/input_arg_mismatch.rs:LL:CC
13+
14+
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
15+
16+
error: aborting due to 1 previous error
17+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//@ignore-target: windows # File handling is not implemented yet
2+
//@compile-flags: -Zmiri-disable-isolation
3+
use std::ffi::{CString, OsStr, c_char, c_int, c_short};
4+
use std::os::unix::ffi::OsStrExt;
5+
6+
extern "C" {
7+
fn open(path: *const c_char, oflag: c_int, ...) -> c_int;
8+
// correct return type is i32
9+
fn close(fd: c_int) -> c_short;
10+
}
11+
12+
fn main() {
13+
let c_path = CString::new(OsStr::new("./text").as_bytes()).expect("CString::new failed");
14+
let fd = unsafe {
15+
open(c_path.as_ptr(), /* value does not matter */ 0)
16+
};
17+
let _ = unsafe {
18+
close(fd);
19+
//~^ ERROR: calling a function with return type i32 passing return place of type i16
20+
};
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
error: Undefined Behavior: calling a function with return type i32 passing return place of type i16
2+
--> tests/fail/shims/return_type_mismatch.rs:LL:CC
3+
|
4+
LL | close(fd);
5+
| ^^^^^^^^^ calling a function with return type i32 passing return place of type i16
6+
|
7+
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
8+
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
9+
= help: this means these two types are not *guaranteed* to be ABI-compatible across all targets
10+
= help: if you think this code should be accepted anyway, please report an issue with Miri
11+
= note: BACKTRACE:
12+
= note: inside `main` at tests/fail/shims/return_type_mismatch.rs:LL:CC
13+
14+
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
15+
16+
error: aborting due to 1 previous error
17+

0 commit comments

Comments
 (0)