Skip to content

Commit f79a22c

Browse files
committed
validate return value on stack pop
1 parent a05914e commit f79a22c

File tree

5 files changed

+59
-35
lines changed

5 files changed

+59
-35
lines changed

src/librustc_mir/const_eval.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ use rustc::mir::interpret::{
3333
Scalar, Allocation, AllocId, ConstValue,
3434
};
3535
use interpret::{self,
36-
Place, PlaceTy, MemPlace, OpTy, Operand, Value,
36+
PlaceTy, MemPlace, OpTy, Operand, Value,
3737
EvalContext, StackPopCleanup, MemoryKind,
3838
snapshot,
3939
};
@@ -55,13 +55,14 @@ pub fn mk_borrowck_eval_cx<'a, 'mir, 'tcx>(
5555
let param_env = tcx.param_env(instance.def_id());
5656
let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeInterpreter::new(), ());
5757
// insert a stack frame so any queries have the correct substs
58+
// cannot use `push_stack_frame`; if we do `const_prop` explodes
5859
ecx.stack.push(interpret::Frame {
5960
block: mir::START_BLOCK,
6061
locals: IndexVec::new(),
6162
instance,
6263
span,
6364
mir,
64-
return_place: Place::null(tcx),
65+
return_place: None,
6566
return_to_block: StackPopCleanup::Goto(None), // never pop
6667
stmt: 0,
6768
});
@@ -82,7 +83,7 @@ pub fn mk_eval_cx<'a, 'tcx>(
8283
instance,
8384
mir.span,
8485
mir,
85-
Place::null(tcx),
86+
None,
8687
StackPopCleanup::Goto(None), // never pop
8788
)?;
8889
Ok(ecx)
@@ -187,7 +188,7 @@ fn eval_body_using_ecx<'mir, 'tcx>(
187188
cid.instance,
188189
mir.span,
189190
mir,
190-
Place::Ptr(*ret),
191+
Some(ret.into()),
191192
StackPopCleanup::None { cleanup: false },
192193
)?;
193194

src/librustc_mir/interpret/eval_context.rs

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use rustc::mir::interpret::{
3131
use syntax::source_map::{self, Span};
3232

3333
use super::{
34-
Value, Operand, MemPlace, MPlaceTy, Place, ScalarMaybeUndef,
34+
Value, Operand, MemPlace, MPlaceTy, Place, PlaceTy, ScalarMaybeUndef,
3535
Memory, Machine
3636
};
3737

@@ -73,8 +73,9 @@ pub struct Frame<'mir, 'tcx: 'mir, Tag=()> {
7373
/// Work to perform when returning from this function
7474
pub return_to_block: StackPopCleanup,
7575

76-
/// The location where the result of the current stack frame should be written to.
77-
pub return_place: Place<Tag>,
76+
/// The location where the result of the current stack frame should be written to,
77+
/// and its layout in the caller.
78+
pub return_place: Option<PlaceTy<'tcx, Tag>>,
7879

7980
/// The list of locals for this stack frame, stored in order as
8081
/// `[return_ptr, arguments..., variables..., temporaries...]`.
@@ -97,7 +98,8 @@ pub struct Frame<'mir, 'tcx: 'mir, Tag=()> {
9798
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
9899
pub enum StackPopCleanup {
99100
/// Jump to the next block in the caller, or cause UB if None (that's a function
100-
/// that may never return).
101+
/// that may never return). Also store layout of return place so
102+
/// we can validate it at that layout.
101103
Goto(Option<mir::BasicBlock>),
102104
/// Just do nohing: Used by Main and for the box_alloc hook in miri.
103105
/// `cleanup` says whether locals are deallocated. Static computation
@@ -424,7 +426,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
424426
instance: ty::Instance<'tcx>,
425427
span: source_map::Span,
426428
mir: &'mir mir::Mir<'tcx>,
427-
return_place: Place<M::PointerTag>,
429+
return_place: Option<PlaceTy<'tcx, M::PointerTag>>,
428430
return_to_block: StackPopCleanup,
429431
) -> EvalResult<'tcx> {
430432
::log_settings::settings().indentation += 1;
@@ -509,15 +511,38 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
509511
}
510512
StackPopCleanup::None { cleanup } => {
511513
if !cleanup {
512-
// Leak the locals
514+
// Leak the locals. Also skip validation, this is only used by
515+
// static/const computation which does its own (stronger) final
516+
// validation.
513517
return Ok(());
514518
}
515519
}
516520
}
517-
// deallocate all locals that are backed by an allocation
521+
// Deallocate all locals that are backed by an allocation.
518522
for local in frame.locals {
519523
self.deallocate_local(local)?;
520524
}
525+
// Validate the return value.
526+
if let Some(return_place) = frame.return_place {
527+
if M::ENFORCE_VALIDITY {
528+
// Data got changed, better make sure it matches the type!
529+
// It is still possible that the return place held invalid data while
530+
// the function is running, but that's okay because nobody could have
531+
// accessed that same data from the "outside" to observe any broken
532+
// invariant -- that is, unless a function somehow has a ptr to
533+
// its return place... but the way MIR is currently generated, the
534+
// return place is always a local and then this cannot happen.
535+
self.validate_operand(
536+
self.place_to_op(return_place)?,
537+
&mut vec![],
538+
None,
539+
/*const_mode*/false,
540+
)?;
541+
}
542+
} else {
543+
// Uh, that shouln't happen... the function did not intend to return
544+
return err!(Unreachable);
545+
}
521546

522547
Ok(())
523548
}

src/librustc_mir/interpret/place.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -256,12 +256,6 @@ impl<'tcx, Tag: ::std::fmt::Debug> Place<Tag> {
256256
}
257257

258258
impl<'tcx, Tag: ::std::fmt::Debug> PlaceTy<'tcx, Tag> {
259-
/// Produces a Place that will error if attempted to be read from or written to
260-
#[inline]
261-
pub fn null(cx: impl HasDataLayout, layout: TyLayout<'tcx>) -> Self {
262-
PlaceTy { place: Place::from_scalar_ptr(Scalar::ptr_null(cx), layout.align), layout }
263-
}
264-
265259
#[inline]
266260
pub fn to_mem_place(self) -> MPlaceTy<'tcx, Tag> {
267261
MPlaceTy { mplace: self.place.to_mem_place(), layout: self.layout }
@@ -565,9 +559,15 @@ where
565559
) -> EvalResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
566560
use rustc::mir::Place::*;
567561
let place = match *mir_place {
568-
Local(mir::RETURN_PLACE) => PlaceTy {
569-
place: self.frame().return_place,
570-
layout: self.layout_of_local(self.cur_frame(), mir::RETURN_PLACE)?,
562+
Local(mir::RETURN_PLACE) => match self.frame().return_place {
563+
Some(return_place) =>
564+
// We use our layout to verify our assumption; caller will validate
565+
// their layout on return.
566+
PlaceTy {
567+
place: *return_place,
568+
layout: self.layout_of_local(self.cur_frame(), mir::RETURN_PLACE)?,
569+
},
570+
None => return err!(InvalidNullPointerUsage),
571571
},
572572
Local(local) => PlaceTy {
573573
place: Place::Local {

src/librustc_mir/interpret/snapshot.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ struct FrameSnapshot<'a, 'tcx: 'a> {
337337
instance: &'a ty::Instance<'tcx>,
338338
span: &'a Span,
339339
return_to_block: &'a StackPopCleanup,
340-
return_place: Place<(), AllocIdSnapshot<'a>>,
340+
return_place: Option<Place<(), AllocIdSnapshot<'a>>>,
341341
locals: IndexVec<mir::Local, LocalValue<(), AllocIdSnapshot<'a>>>,
342342
block: &'a mir::BasicBlock,
343343
stmt: usize,
@@ -362,7 +362,7 @@ impl<'a, 'mir, 'tcx: 'mir> HashStable<StableHashingContext<'a>> for Frame<'mir,
362362
} = self;
363363

364364
(mir, instance, span, return_to_block).hash_stable(hcx, hasher);
365-
(return_place, locals, block, stmt).hash_stable(hcx, hasher);
365+
(return_place.as_ref().map(|r| &**r), locals, block, stmt).hash_stable(hcx, hasher);
366366
}
367367
}
368368
impl<'a, 'mir, 'tcx, Ctx> Snapshot<'a, Ctx> for &'a Frame<'mir, 'tcx>
@@ -388,7 +388,7 @@ impl<'a, 'mir, 'tcx, Ctx> Snapshot<'a, Ctx> for &'a Frame<'mir, 'tcx>
388388
return_to_block,
389389
block,
390390
stmt: *stmt,
391-
return_place: return_place.snapshot(ctx),
391+
return_place: return_place.map(|r| r.snapshot(ctx)),
392392
locals: locals.iter().map(|local| local.snapshot(ctx)).collect(),
393393
}
394394
}

src/librustc_mir/interpret/terminator.rs

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use rustc_target::spec::abi::Abi;
1717

1818
use rustc::mir::interpret::{EvalResult, PointerArithmetic, EvalErrorKind, Scalar};
1919
use super::{
20-
EvalContext, Machine, Value, OpTy, Place, PlaceTy, Operand, StackPopCleanup
20+
EvalContext, Machine, Value, OpTy, PlaceTy, MPlaceTy, Operand, StackPopCleanup
2121
};
2222

2323
impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
@@ -39,7 +39,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
3939
use rustc::mir::TerminatorKind::*;
4040
match terminator.kind {
4141
Return => {
42-
self.dump_place(self.frame().return_place);
42+
self.frame().return_place.map(|r| self.dump_place(*r));
4343
self.pop_stack_frame()?
4444
}
4545

@@ -286,15 +286,11 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
286286
None => return Ok(()),
287287
};
288288

289-
let return_place = match dest {
290-
Some(place) => *place,
291-
None => Place::null(&self), // any access will error. good!
292-
};
293289
self.push_stack_frame(
294290
instance,
295291
span,
296292
mir,
297-
return_place,
293+
dest,
298294
StackPopCleanup::Goto(ret),
299295
)?;
300296

@@ -375,17 +371,19 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
375371
return err!(FunctionArgCountMismatch);
376372
}
377373
// Don't forget to check the return type!
378-
let callee_ret = self.eval_place(&mir::Place::Local(mir::RETURN_PLACE))?;
379374
if let Some(caller_ret) = dest {
375+
let callee_ret = self.eval_place(&mir::Place::Local(mir::RETURN_PLACE))?;
380376
if !Self::check_argument_compat(caller_ret.layout, callee_ret.layout) {
381377
return err!(FunctionRetMismatch(
382378
caller_ret.layout.ty, callee_ret.layout.ty
383379
));
384380
}
385381
} else {
386-
if !callee_ret.layout.abi.is_uninhabited() {
382+
let callee_layout =
383+
self.layout_of_local(self.cur_frame(), mir::RETURN_PLACE)?;
384+
if !callee_layout.abi.is_uninhabited() {
387385
return err!(FunctionRetMismatch(
388-
self.tcx.types.never, callee_ret.layout.ty
386+
self.tcx.types.never, callee_layout.ty
389387
));
390388
}
391389
}
@@ -453,14 +451,14 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
453451
};
454452

455453
let ty = self.tcx.mk_unit(); // return type is ()
456-
let dest = PlaceTy::null(&self, self.layout_of(ty)?);
454+
let dest = MPlaceTy::dangling(self.layout_of(ty)?, &self);
457455

458456
self.eval_fn_call(
459457
instance,
460458
span,
461459
Abi::Rust,
462460
&[arg],
463-
Some(dest),
461+
Some(dest.into()),
464462
Some(target),
465463
)
466464
}

0 commit comments

Comments
 (0)