Skip to content

Commit 0788188

Browse files
committed
Auto merge of #1743 - RalfJung:callee-checks, r=RalfJung
Check callee ABI when Miri calls closures Fixes #1741
2 parents a798792 + d1dec9c commit 0788188

File tree

9 files changed

+82
-3
lines changed

9 files changed

+82
-3
lines changed

src/eval.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use log::info;
88
use rustc_hir::def_id::DefId;
99
use rustc_middle::ty::{self, layout::LayoutCx, TyCtxt};
1010
use rustc_target::abi::LayoutOf;
11+
use rustc_target::spec::abi::Abi;
1112

1213
use crate::*;
1314

@@ -189,6 +190,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
189190
// Call start function.
190191
ecx.call_function(
191192
start_instance,
193+
Abi::Rust,
192194
&[main_ptr.into(), argc.into(), argv.into()],
193195
Some(&ret_place.into()),
194196
StackPopCleanup::None { cleanup: true },

src/helpers.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,11 +161,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
161161
fn call_function(
162162
&mut self,
163163
f: ty::Instance<'tcx>,
164+
caller_abi: Abi,
164165
args: &[Immediate<Tag>],
165166
dest: Option<&PlaceTy<'tcx, Tag>>,
166167
stack_pop: StackPopCleanup,
167168
) -> InterpResult<'tcx> {
168169
let this = self.eval_context_mut();
170+
let param_env = ty::ParamEnv::reveal_all(); // in Miri this is always the param_env we use... and this.param_env is private.
171+
let callee_abi = f.ty(*this.tcx, param_env).fn_sig(*this.tcx).abi();
172+
if callee_abi != caller_abi {
173+
throw_ub_format!("calling a function with ABI {} using caller ABI {}", callee_abi.name(), caller_abi.name())
174+
}
169175

170176
// Push frame.
171177
let mir = &*this.load_mir(f.def, None)?;
@@ -175,11 +181,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
175181
let mut callee_args = this.frame().body.args_iter();
176182
for arg in args {
177183
let callee_arg = this.local_place(
178-
callee_args.next().expect("callee has fewer arguments than expected"),
184+
callee_args.next().ok_or_else(||
185+
err_ub_format!("callee has fewer arguments than expected")
186+
)?
179187
)?;
180188
this.write_immediate(*arg, &callee_arg)?;
181189
}
182-
assert_eq!(callee_args.next(), None, "callee has more arguments than expected");
190+
if callee_args.next().is_some() {
191+
throw_ub_format!("callee has more arguments than expected");
192+
}
183193

184194
Ok(())
185195
}

src/machine.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> {
430430
let malloc = ty::Instance::mono(ecx.tcx.tcx, malloc);
431431
ecx.call_function(
432432
malloc,
433+
Abi::Rust,
433434
&[size.into(), align.into()],
434435
Some(dest),
435436
// Don't do anything when we are done. The `statement()` function will increment

src/shims/panic.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use log::trace;
1515

1616
use rustc_middle::{mir, ty};
1717
use rustc_target::spec::PanicStrategy;
18+
use rustc_target::spec::abi::Abi;
1819

1920
use crate::*;
2021
use helpers::check_arg_count;
@@ -96,6 +97,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
9697
let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into();
9798
this.call_function(
9899
f_instance,
100+
Abi::Rust,
99101
&[data.into()],
100102
Some(&ret_place),
101103
// Directly return to caller.
@@ -147,6 +149,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
147149
let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into();
148150
this.call_function(
149151
f_instance,
152+
Abi::Rust,
150153
&[catch_unwind.data.into(), payload.into()],
151154
Some(&ret_place),
152155
// Directly return to caller of `try`.
@@ -176,6 +179,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
176179
let panic = ty::Instance::mono(this.tcx.tcx, panic);
177180
this.call_function(
178181
panic,
182+
Abi::Rust,
179183
&[msg.to_ref()],
180184
None,
181185
StackPopCleanup::Goto { ret: None, unwind },
@@ -204,6 +208,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
204208
let panic_bounds_check = ty::Instance::mono(this.tcx.tcx, panic_bounds_check);
205209
this.call_function(
206210
panic_bounds_check,
211+
Abi::Rust,
207212
&[index.into(), len.into()],
208213
None,
209214
StackPopCleanup::Goto { ret: None, unwind },

src/shims/posix/thread.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use std::convert::TryInto;
22

33
use crate::*;
44
use rustc_target::abi::LayoutOf;
5+
use rustc_target::spec::abi::Abi;
56

67
impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
78
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
@@ -50,6 +51,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
5051

5152
this.call_function(
5253
instance,
54+
Abi::C { unwind: false },
5355
&[*func_arg],
5456
Some(&ret_place.into()),
5557
StackPopCleanup::None { cleanup: true },

src/shims/tls.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use log::trace;
99
use rustc_data_structures::fx::FxHashMap;
1010
use rustc_middle::ty;
1111
use rustc_target::abi::{Size, HasDataLayout};
12+
use rustc_target::spec::abi::Abi;
1213

1314
use crate::*;
1415

@@ -244,6 +245,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
244245
let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into();
245246
this.call_function(
246247
thread_callback,
248+
Abi::System { unwind: false },
247249
&[Scalar::null_ptr(this).into(), reason.into(), Scalar::null_ptr(this).into()],
248250
Some(&ret_place),
249251
StackPopCleanup::None { cleanup: true },
@@ -266,6 +268,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
266268
let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into();
267269
this.call_function(
268270
instance,
271+
Abi::C { unwind: false },
269272
&[data.into()],
270273
Some(&ret_place),
271274
StackPopCleanup::None { cleanup: true },
@@ -306,6 +309,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
306309
let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into();
307310
this.call_function(
308311
instance,
312+
Abi::C { unwind: false },
309313
&[ptr.into()],
310314
Some(&ret_place),
311315
StackPopCleanup::None { cleanup: true },
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// ignore-windows: Concurrency on Windows is not supported yet.
2+
// error-pattern: callee has fewer arguments than expected
3+
4+
//! The thread function must have exactly one argument.
5+
6+
#![feature(rustc_private)]
7+
8+
extern crate libc;
9+
10+
use std::{mem, ptr};
11+
12+
extern "C" fn thread_start() -> *mut libc::c_void {
13+
panic!()
14+
}
15+
16+
fn main() {
17+
unsafe {
18+
let mut native: libc::pthread_t = mem::zeroed();
19+
let attr: libc::pthread_attr_t = mem::zeroed();
20+
// assert_eq!(libc::pthread_attr_init(&mut attr), 0); FIXME: this function is not yet implemented.
21+
let thread_start: extern "C" fn() -> *mut libc::c_void = thread_start;
22+
let thread_start: extern "C" fn(*mut libc::c_void) -> *mut libc::c_void = mem::transmute(thread_start);
23+
assert_eq!(libc::pthread_create(&mut native, &attr, thread_start, ptr::null_mut()), 0);
24+
assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0);
25+
}
26+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// ignore-windows: Concurrency on Windows is not supported yet.
2+
// error-pattern: callee has more arguments than expected
3+
4+
//! The thread function must have exactly one argument.
5+
6+
#![feature(rustc_private)]
7+
8+
extern crate libc;
9+
10+
use std::{mem, ptr};
11+
12+
extern "C" fn thread_start(_null: *mut libc::c_void, _x: i32) -> *mut libc::c_void {
13+
panic!()
14+
}
15+
16+
fn main() {
17+
unsafe {
18+
let mut native: libc::pthread_t = mem::zeroed();
19+
let attr: libc::pthread_attr_t = mem::zeroed();
20+
// assert_eq!(libc::pthread_attr_init(&mut attr), 0); FIXME: this function is not yet implemented.
21+
let thread_start: extern "C" fn(*mut libc::c_void, i32) -> *mut libc::c_void = thread_start;
22+
let thread_start: extern "C" fn(*mut libc::c_void) -> *mut libc::c_void = mem::transmute(thread_start);
23+
assert_eq!(libc::pthread_create(&mut native, &attr, thread_start, ptr::null_mut()), 0);
24+
assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0);
25+
}
26+
}

tests/compile-fail/concurrency/unwind_top_of_stack.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
// ignore-windows: Concurrency on Windows is not supported yet.
2-
// error-pattern: unwinding past the topmost frame of the stack
2+
// error-pattern: calling a function with ABI C-unwind using caller ABI C
33

44
//! Unwinding past the top frame of a stack is Undefined Behavior.
5+
//! However, it is impossible to do that in pure Rust since one cannot write an unwinding
6+
//! function with `C` ABI... so let's instead test that we are indeed correctly checking
7+
//! the callee ABI in `pthread_create`.
58
69
#![feature(rustc_private, c_unwind)]
710

0 commit comments

Comments
 (0)