Skip to content

Commit 9a6df47

Browse files
committed
miri engine: also check return type before calling function
1 parent 9d293d1 commit 9a6df47

File tree

6 files changed

+36
-2
lines changed

6 files changed

+36
-2
lines changed

src/librustc/ich/impls_ty.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,10 @@ for ::mir::interpret::EvalErrorKind<'gcx, O> {
560560
a.hash_stable(hcx, hasher);
561561
b.hash_stable(hcx, hasher)
562562
},
563+
FunctionRetMismatch(a, b) => {
564+
a.hash_stable(hcx, hasher);
565+
b.hash_stable(hcx, hasher)
566+
},
563567
NoMirFor(ref s) => s.hash_stable(hcx, hasher),
564568
UnterminatedCString(ptr) => ptr.hash_stable(hcx, hasher),
565569
PointerOutOfBounds {

src/librustc/mir/interpret/error.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ pub enum EvalErrorKind<'tcx, O> {
186186

187187
FunctionAbiMismatch(Abi, Abi),
188188
FunctionArgMismatch(Ty<'tcx>, Ty<'tcx>),
189+
FunctionRetMismatch(Ty<'tcx>, Ty<'tcx>),
189190
FunctionArgCountMismatch,
190191
NoMirFor(String),
191192
UnterminatedCString(Pointer),
@@ -294,7 +295,8 @@ impl<'tcx, O> EvalErrorKind<'tcx, O> {
294295
use self::EvalErrorKind::*;
295296
match *self {
296297
MachineError(ref inner) => inner,
297-
FunctionAbiMismatch(..) | FunctionArgMismatch(..) | FunctionArgCountMismatch =>
298+
FunctionAbiMismatch(..) | FunctionArgMismatch(..) | FunctionRetMismatch(..)
299+
| FunctionArgCountMismatch =>
298300
"tried to call a function through a function pointer of incompatible type",
299301
InvalidMemoryAccess =>
300302
"tried to access memory through an invalid pointer",
@@ -470,6 +472,10 @@ impl<'tcx, O: fmt::Debug> fmt::Debug for EvalErrorKind<'tcx, O> {
470472
write!(f, "tried to call a function with argument of type {:?} \
471473
passing data of type {:?}",
472474
callee_ty, caller_ty),
475+
FunctionRetMismatch(caller_ty, callee_ty) =>
476+
write!(f, "tried to call a function with return type {:?} \
477+
passing return place of type {:?}",
478+
callee_ty, caller_ty),
473479
FunctionArgCountMismatch =>
474480
write!(f, "tried to call a function with incorrect number of arguments"),
475481
BoundsCheck { ref len, ref index } =>

src/librustc/ty/structural_impls.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,10 @@ impl<'a, 'tcx, O: Lift<'tcx>> Lift<'tcx> for interpret::EvalErrorKind<'a, O> {
493493
tcx.lift(&a)?,
494494
tcx.lift(&b)?,
495495
),
496+
FunctionRetMismatch(a, b) => FunctionRetMismatch(
497+
tcx.lift(&a)?,
498+
tcx.lift(&b)?,
499+
),
496500
FunctionArgCountMismatch => FunctionArgCountMismatch,
497501
NoMirFor(ref s) => NoMirFor(s.clone()),
498502
UnterminatedCString(ptr) => UnterminatedCString(ptr),

src/librustc_mir/interpret/eval_context.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
231231
/// Mark a storage as live, killing the previous content and returning it.
232232
/// Remember to deallocate that!
233233
pub fn storage_live(&mut self, local: mir::Local) -> EvalResult<'tcx, LocalValue> {
234+
assert!(local != mir::RETURN_PLACE, "Cannot make return place live");
234235
trace!("{:?} is now live", local);
235236

236237
let layout = self.layout_of_local(self.cur_frame(), local)?;
@@ -242,6 +243,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
242243
/// Returns the old value of the local.
243244
/// Remember to deallocate that!
244245
pub fn storage_dead(&mut self, local: mir::Local) -> LocalValue {
246+
assert!(local != mir::RETURN_PLACE, "Cannot make return place dead");
245247
trace!("{:?} is now dead", local);
246248

247249
mem::replace(&mut self.frame_mut().locals[local], LocalValue::Dead)
@@ -446,6 +448,9 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
446448
let dummy =
447449
LocalValue::Live(Operand::Immediate(Value::Scalar(ScalarMaybeUndef::Undef)));
448450
let mut locals = IndexVec::from_elem(dummy, &mir.local_decls);
451+
// Return place is handled specially by the `eval_place` functions, and the
452+
// entry in `locals` should never be used. Make it dead, to be sure.
453+
locals[mir::RETURN_PLACE] = LocalValue::Dead;
449454
// Now mark those locals as dead that we do not want to initialize
450455
match self.tcx.describe_def(instance.def_id()) {
451456
// statics and constants don't have `Storage*` statements, no need to look for them

src/librustc_mir/interpret/terminator.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
287287

288288
let return_place = match dest {
289289
Some(place) => *place,
290-
None => Place::null(&self),
290+
None => Place::null(&self), // any access will error. good!
291291
};
292292
self.push_stack_frame(
293293
instance,
@@ -373,6 +373,20 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
373373
trace!("Caller has too many args over");
374374
return err!(FunctionArgCountMismatch);
375375
}
376+
// Don't forget to check the return type!
377+
if let Some(caller_ret) = dest {
378+
let callee_ret = self.eval_place(&mir::Place::Local(mir::RETURN_PLACE))?;
379+
if !Self::check_argument_compat(caller_ret.layout, callee_ret.layout) {
380+
return err!(FunctionRetMismatch(
381+
caller_ret.layout.ty, callee_ret.layout.ty
382+
));
383+
}
384+
} else {
385+
// FIXME: The caller thinks this function cannot return. How do
386+
// we verify that the callee agrees?
387+
// On the plus side, the the callee every writes to its return place,
388+
// that will be detected as UB (because we set that to NULL above).
389+
}
376390
Ok(())
377391
})();
378392
match res {

src/librustc_mir/transform/const_prop.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
154154
// FIXME: figure out the rules and start linting
155155
| FunctionAbiMismatch(..)
156156
| FunctionArgMismatch(..)
157+
| FunctionRetMismatch(..)
157158
| FunctionArgCountMismatch
158159
// fine at runtime, might be a register address or sth
159160
| ReadBytesAsPointer

0 commit comments

Comments
 (0)