Skip to content

Commit

Permalink
Merge pull request rust-lang#351 from RalfJung/exchange_malloc
Browse files Browse the repository at this point in the history
Call exchange_malloc for box stmt
  • Loading branch information
oli-obk authored Sep 27, 2017
2 parents a5503a3 + 6e86503 commit ed674f7
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 18 deletions.
5 changes: 4 additions & 1 deletion miri/fn_call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,9 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator>
Lvalue::undef(),
StackPopCleanup::Goto(dest_block),
)?;
let mut args = self.frame().mir.args_iter();

let arg_local = self.frame().mir.args_iter().next().ok_or(
let arg_local = args.next().ok_or(
EvalErrorKind::AbiViolation(
"Argument to __rust_maybe_catch_panic does not take enough arguments."
.to_owned(),
Expand All @@ -186,6 +187,8 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator>
let arg_dest = self.eval_lvalue(&mir::Lvalue::Local(arg_local))?;
self.write_ptr(arg_dest, data, u8_ptr_ty)?;

assert!(args.next().is_none(), "__rust_maybe_catch_panic argument has more arguments than expected");

// We ourselves return 0
self.write_null(dest, dest_ty)?;

Expand Down
59 changes: 50 additions & 9 deletions miri/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ pub fn eval_main<'a, 'tcx: 'a>(
ecx.memory.write_primval(foo_ptr.into(), PrimVal::Ptr(foo.into()), ptr_size, false)?;
ecx.memory.mark_static_initalized(foo_ptr.alloc_id, Mutability::Immutable)?;
ecx.write_ptr(dest, foo_ptr.into(), ty)?;

assert!(args.next().is_none(), "start lang item has more arguments than expected");
} else {
ecx.push_stack_frame(
main_instance,
Expand All @@ -122,6 +124,10 @@ pub fn eval_main<'a, 'tcx: 'a>(
Lvalue::undef(),
StackPopCleanup::None,
)?;

// No arguments
let mut args = ecx.frame().mir.args_iter();
assert!(args.next().is_none(), "main function must not have arguments");
}

while ecx.step()? {}
Expand Down Expand Up @@ -227,17 +233,52 @@ impl<'tcx> Machine<'tcx> for Evaluator {
fn box_alloc<'a>(
ecx: &mut EvalContext<'a, 'tcx, Self>,
ty: ty::Ty<'tcx>,
) -> EvalResult<'tcx, PrimVal> {
// FIXME: call the `exchange_malloc` lang item if available
dest: Lvalue,
) -> EvalResult<'tcx> {
let size = ecx.type_size(ty)?.expect("box only works with sized types");
let align = ecx.type_align(ty)?;
if size == 0 {
Ok(PrimVal::Bytes(align.into()))
} else {
ecx.memory
.allocate(size, align, MemoryKind::Machine(memory::MemoryKind::Rust))
.map(PrimVal::Ptr)
}

// Call the `exchange_malloc` lang item
let malloc = ecx.tcx.lang_items().exchange_malloc_fn().unwrap();
let malloc = ty::Instance::mono(ecx.tcx, malloc);
let malloc_mir = ecx.load_mir(malloc.def)?;
ecx.push_stack_frame(
malloc,
malloc_mir.span,
malloc_mir,
dest,
// Don't do anything when we are done. The statement() function will increment
// the old stack frame's stmt counter to the next statement, which means that when
// exchange_malloc returns, we go on evaluating exactly where we want to be.
StackPopCleanup::None,
)?;

let mut args = ecx.frame().mir.args_iter();
let usize = ecx.tcx.types.usize;

// First argument: size
let dest = ecx.eval_lvalue(&mir::Lvalue::Local(args.next().unwrap()))?;
ecx.write_value(
ValTy {
value: Value::ByVal(PrimVal::Bytes(size as u128)),
ty: usize,
},
dest,
)?;

// Second argument: align
let dest = ecx.eval_lvalue(&mir::Lvalue::Local(args.next().unwrap()))?;
ecx.write_value(
ValTy {
value: Value::ByVal(PrimVal::Bytes(align as u128)),
ty: usize,
},
dest,
)?;

// No more arguments
assert!(args.next().is_none(), "exchange_malloc lang item has more arguments than expected");
Ok(())
}

fn global_item_with_linkage<'a>(
Expand Down
3 changes: 2 additions & 1 deletion src/librustc_mir/interpret/const_eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,8 @@ impl<'tcx> super::Machine<'tcx> for CompileTimeFunctionEvaluator {
fn box_alloc<'a>(
_ecx: &mut EvalContext<'a, 'tcx, Self>,
_ty: ty::Ty<'tcx>,
) -> EvalResult<'tcx, PrimVal> {
_dest: Lvalue,
) -> EvalResult<'tcx> {
Err(
ConstEvalError::NeedsRfc("Heap allocations via `box` keyword".to_string()).into(),
)
Expand Down
3 changes: 1 addition & 2 deletions src/librustc_mir/interpret/eval_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -877,8 +877,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
}

NullaryOp(mir::NullOp::Box, ty) => {
let ptr = M::box_alloc(self, ty)?;
self.write_primval(dest, ptr, dest_ty)?;
M::box_alloc(self, ty, dest)?;
}

NullaryOp(mir::NullOp::SizeOf, ty) => {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_mir/interpret/lvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -497,7 +497,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
Ok(Lvalue::Ptr { ptr, extra })
}

pub(super) fn lvalue_ty(&self, lvalue: &mir::Lvalue<'tcx>) -> Ty<'tcx> {
pub fn lvalue_ty(&self, lvalue: &mir::Lvalue<'tcx>) -> Ty<'tcx> {
self.monomorphize(
lvalue.ty(self.mir(), self.tcx).to_ty(self.tcx),
self.substs(),
Expand Down
3 changes: 2 additions & 1 deletion src/librustc_mir/interpret/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ pub trait Machine<'tcx>: Sized {
fn box_alloc<'a>(
ecx: &mut EvalContext<'a, 'tcx, Self>,
ty: ty::Ty<'tcx>,
) -> EvalResult<'tcx, PrimVal>;
dest: Lvalue,
) -> EvalResult<'tcx>;

/// Called when trying to access a global declared with a `linkage` attribute
fn global_item_with_linkage<'a>(
Expand Down
7 changes: 6 additions & 1 deletion src/librustc_mir/interpret/step.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,11 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
trace!("{:?}", stmt);

use rustc::mir::StatementKind::*;

// Some statements (e.g. box) push new stack frames. We have to record the stack frame number
// *before* executing the statement.
let frame_idx = self.cur_frame();

match stmt.kind {
Assign(ref lvalue, ref rvalue) => self.eval_rvalue_into_lvalue(rvalue, lvalue)?,

Expand Down Expand Up @@ -175,7 +180,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
InlineAsm { .. } => return err!(InlineAsm),
}

self.frame_mut().stmt += 1;
self.stack[frame_idx].stmt += 1;
Ok(())
}

Expand Down
8 changes: 6 additions & 2 deletions tests/compile-fail/oom2.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
// Validation forces more allocation; disable it.
// compile-flags: -Zmir-emit-validate=0
#![feature(box_syntax, custom_attribute, attr_literals)]
#![miri(memory_size=2048)]
#![miri(memory_size=1024)]

// On 64bit platforms, the allocator needs 32 bytes allocated to pass a return value, so that's the error we see.
// On 32bit platforms, it's just 16 bytes.
// error-pattern: tried to allocate

fn main() {
loop {
::std::mem::forget(box 42); //~ ERROR tried to allocate 4 more bytes
::std::mem::forget(box 42);
}
}

0 comments on commit ed674f7

Please sign in to comment.