Skip to content

Commit ed674f7

Browse files
authored
Merge pull request #351 from RalfJung/exchange_malloc
Call exchange_malloc for box stmt
2 parents a5503a3 + 6e86503 commit ed674f7

File tree

8 files changed

+72
-18
lines changed

8 files changed

+72
-18
lines changed

miri/fn_call.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,9 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator>
176176
Lvalue::undef(),
177177
StackPopCleanup::Goto(dest_block),
178178
)?;
179+
let mut args = self.frame().mir.args_iter();
179180

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

190+
assert!(args.next().is_none(), "__rust_maybe_catch_panic argument has more arguments than expected");
191+
189192
// We ourselves return 0
190193
self.write_null(dest, dest_ty)?;
191194

miri/lib.rs

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ pub fn eval_main<'a, 'tcx: 'a>(
114114
ecx.memory.write_primval(foo_ptr.into(), PrimVal::Ptr(foo.into()), ptr_size, false)?;
115115
ecx.memory.mark_static_initalized(foo_ptr.alloc_id, Mutability::Immutable)?;
116116
ecx.write_ptr(dest, foo_ptr.into(), ty)?;
117+
118+
assert!(args.next().is_none(), "start lang item has more arguments than expected");
117119
} else {
118120
ecx.push_stack_frame(
119121
main_instance,
@@ -122,6 +124,10 @@ pub fn eval_main<'a, 'tcx: 'a>(
122124
Lvalue::undef(),
123125
StackPopCleanup::None,
124126
)?;
127+
128+
// No arguments
129+
let mut args = ecx.frame().mir.args_iter();
130+
assert!(args.next().is_none(), "main function must not have arguments");
125131
}
126132

127133
while ecx.step()? {}
@@ -227,17 +233,52 @@ impl<'tcx> Machine<'tcx> for Evaluator {
227233
fn box_alloc<'a>(
228234
ecx: &mut EvalContext<'a, 'tcx, Self>,
229235
ty: ty::Ty<'tcx>,
230-
) -> EvalResult<'tcx, PrimVal> {
231-
// FIXME: call the `exchange_malloc` lang item if available
236+
dest: Lvalue,
237+
) -> EvalResult<'tcx> {
232238
let size = ecx.type_size(ty)?.expect("box only works with sized types");
233239
let align = ecx.type_align(ty)?;
234-
if size == 0 {
235-
Ok(PrimVal::Bytes(align.into()))
236-
} else {
237-
ecx.memory
238-
.allocate(size, align, MemoryKind::Machine(memory::MemoryKind::Rust))
239-
.map(PrimVal::Ptr)
240-
}
240+
241+
// Call the `exchange_malloc` lang item
242+
let malloc = ecx.tcx.lang_items().exchange_malloc_fn().unwrap();
243+
let malloc = ty::Instance::mono(ecx.tcx, malloc);
244+
let malloc_mir = ecx.load_mir(malloc.def)?;
245+
ecx.push_stack_frame(
246+
malloc,
247+
malloc_mir.span,
248+
malloc_mir,
249+
dest,
250+
// Don't do anything when we are done. The statement() function will increment
251+
// the old stack frame's stmt counter to the next statement, which means that when
252+
// exchange_malloc returns, we go on evaluating exactly where we want to be.
253+
StackPopCleanup::None,
254+
)?;
255+
256+
let mut args = ecx.frame().mir.args_iter();
257+
let usize = ecx.tcx.types.usize;
258+
259+
// First argument: size
260+
let dest = ecx.eval_lvalue(&mir::Lvalue::Local(args.next().unwrap()))?;
261+
ecx.write_value(
262+
ValTy {
263+
value: Value::ByVal(PrimVal::Bytes(size as u128)),
264+
ty: usize,
265+
},
266+
dest,
267+
)?;
268+
269+
// Second argument: align
270+
let dest = ecx.eval_lvalue(&mir::Lvalue::Local(args.next().unwrap()))?;
271+
ecx.write_value(
272+
ValTy {
273+
value: Value::ByVal(PrimVal::Bytes(align as u128)),
274+
ty: usize,
275+
},
276+
dest,
277+
)?;
278+
279+
// No more arguments
280+
assert!(args.next().is_none(), "exchange_malloc lang item has more arguments than expected");
281+
Ok(())
241282
}
242283

243284
fn global_item_with_linkage<'a>(

src/librustc_mir/interpret/const_eval.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,8 @@ impl<'tcx> super::Machine<'tcx> for CompileTimeFunctionEvaluator {
240240
fn box_alloc<'a>(
241241
_ecx: &mut EvalContext<'a, 'tcx, Self>,
242242
_ty: ty::Ty<'tcx>,
243-
) -> EvalResult<'tcx, PrimVal> {
243+
_dest: Lvalue,
244+
) -> EvalResult<'tcx> {
244245
Err(
245246
ConstEvalError::NeedsRfc("Heap allocations via `box` keyword".to_string()).into(),
246247
)

src/librustc_mir/interpret/eval_context.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -877,8 +877,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
877877
}
878878

879879
NullaryOp(mir::NullOp::Box, ty) => {
880-
let ptr = M::box_alloc(self, ty)?;
881-
self.write_primval(dest, ptr, dest_ty)?;
880+
M::box_alloc(self, ty, dest)?;
882881
}
883882

884883
NullaryOp(mir::NullOp::SizeOf, ty) => {

src/librustc_mir/interpret/lvalue.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -497,7 +497,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
497497
Ok(Lvalue::Ptr { ptr, extra })
498498
}
499499

500-
pub(super) fn lvalue_ty(&self, lvalue: &mir::Lvalue<'tcx>) -> Ty<'tcx> {
500+
pub fn lvalue_ty(&self, lvalue: &mir::Lvalue<'tcx>) -> Ty<'tcx> {
501501
self.monomorphize(
502502
lvalue.ty(self.mir(), self.tcx).to_ty(self.tcx),
503503
self.substs(),

src/librustc_mir/interpret/machine.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ pub trait Machine<'tcx>: Sized {
7070
fn box_alloc<'a>(
7171
ecx: &mut EvalContext<'a, 'tcx, Self>,
7272
ty: ty::Ty<'tcx>,
73-
) -> EvalResult<'tcx, PrimVal>;
73+
dest: Lvalue,
74+
) -> EvalResult<'tcx>;
7475

7576
/// Called when trying to access a global declared with a `linkage` attribute
7677
fn global_item_with_linkage<'a>(

src/librustc_mir/interpret/step.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,11 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
9292
trace!("{:?}", stmt);
9393

9494
use rustc::mir::StatementKind::*;
95+
96+
// Some statements (e.g. box) push new stack frames. We have to record the stack frame number
97+
// *before* executing the statement.
98+
let frame_idx = self.cur_frame();
99+
95100
match stmt.kind {
96101
Assign(ref lvalue, ref rvalue) => self.eval_rvalue_into_lvalue(rvalue, lvalue)?,
97102

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

178-
self.frame_mut().stmt += 1;
183+
self.stack[frame_idx].stmt += 1;
179184
Ok(())
180185
}
181186

tests/compile-fail/oom2.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
// Validation forces more allocation; disable it.
22
// compile-flags: -Zmir-emit-validate=0
33
#![feature(box_syntax, custom_attribute, attr_literals)]
4-
#![miri(memory_size=2048)]
4+
#![miri(memory_size=1024)]
5+
6+
// On 64bit platforms, the allocator needs 32 bytes allocated to pass a return value, so that's the error we see.
7+
// On 32bit platforms, it's just 16 bytes.
8+
// error-pattern: tried to allocate
59

610
fn main() {
711
loop {
8-
::std::mem::forget(box 42); //~ ERROR tried to allocate 4 more bytes
12+
::std::mem::forget(box 42);
913
}
1014
}

0 commit comments

Comments
 (0)