Skip to content

Call exchange_malloc for box stmt #351

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Sep 27, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
}
}