Skip to content

Commit 6d195bc

Browse files
committed
Get it working
1 parent e1c42e5 commit 6d195bc

File tree

3 files changed

+81
-12
lines changed

3 files changed

+81
-12
lines changed

src/fn_call.rs

+17-5
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<'
1818
args: &[OpTy<'tcx, Tag>],
1919
dest: Option<PlaceTy<'tcx, Tag>>,
2020
ret: Option<mir::BasicBlock>,
21+
unwind: Option<mir::BasicBlock>
2122
) -> EvalResult<'tcx, Option<&'mir mir::Mir<'tcx>>> {
2223
let this = self.eval_context_mut();
2324
trace!("eval_fn_call: {:#?}, {:?} {:?}", instance, instance.def_id(), dest.map(|place| *place));
@@ -48,7 +49,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<'
4849
if this.tcx.is_foreign_item(instance.def_id()) {
4950
// An external function that we (possibly) cannot find MIR for, but we can still run enough
5051
// of them to make miri viable.
51-
return Ok(this.emulate_foreign_item(instance, args, dest, ret)?);
52+
return Ok(this.emulate_foreign_item(instance, args, dest, ret, unwind)?);
5253
}
5354

5455
// Otherwise, load the MIR.
@@ -143,6 +144,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<'
143144
args: &[OpTy<'tcx, Tag>],
144145
dest: Option<PlaceTy<'tcx, Tag>>,
145146
ret: Option<mir::BasicBlock>,
147+
unwind: Option<mir::BasicBlock>
146148
) -> EvalResult<'tcx, Option<&'mir mir::Mir<'tcx>>> {
147149
let def_id = instance.def_id();
148150
let this = self.eval_context_mut();
@@ -220,6 +222,8 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<'
220222
return err!(MachineError("the evaluated program abort-panicked".to_string()));
221223
}
222224

225+
//this.machine.unwinding = true;
226+
223227
// This part is tricky - we need to call BoxMeUp::box_me_up
224228
// on the vtable.
225229
//
@@ -281,6 +285,8 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<'
281285
// '*mut (dyn Any + Send)', which is a fat
282286

283287
let temp_ptr = this.allocate(dyn_ptr_layout, MiriMemoryKind::UnwindHelper.into());
288+
this.machine.box_me_up_tmp_ptr = Some(temp_ptr.clone());
289+
284290

285291
// Keep track of our current frame
286292
// This allows us to step throgh the exection of 'box_me_up',
@@ -292,14 +298,19 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<'
292298
box_me_up_mir.span,
293299
box_me_up_mir,
294300
Some(temp_ptr.into()),
295-
StackPopCleanup::None { cleanup: true, unwind: None }
301+
// We know that this frame will always be unwound,
302+
// since we enable unwinding as soon as we encounter it
303+
// in Evaluator::stack_pop
304+
StackPopCleanup::Goto { ret: None, unwind }
296305
)?;
297306

307+
this.frame_mut().extra.is_box_me_frame = true;
308+
298309
let mut args = this.frame().mir.args_iter();
299310
let arg_0 = this.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?;
300311
this.write_scalar(data_ptr, arg_0)?;
301312

302-
// Step through execution of 'box_me_up'
313+
/*// Step through execution of 'box_me_up'
303314
// We know that we're finished when our stack depth
304315
// returns to where it was before.
305316
//
@@ -343,7 +354,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<'
343354
unwind_stack(this, real_ret_data, real_ret_vtable)?;
344355
345356
this.memory_mut().deallocate(temp_ptr.to_ptr()?, None, MiriMemoryKind::UnwindHelper.into())?;
346-
this.dump_place(*dest.expect("dest is None!"));
357+
this.dump_place(*dest.expect("dest is None!"));*/
347358

348359
return Ok(None)
349360

@@ -551,7 +562,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<'
551562
data_ptr,
552563
vtable_ptr,
553564
dest: dest.clone(),
554-
ret
565+
ret,
555566
})
556567
}
557568

@@ -1177,6 +1188,7 @@ fn unwind_stack<'a, 'mir, 'tcx>(
11771188
// with 'catch_panic'. When we find this marker, we've found
11781189
// our target frame to jump to.
11791190
if let Some(unwind_data) = this.frame_mut().extra.catch_panic.take() {
1191+
11801192
trace!("unwinding: found target frame: {:?}", this.frame().span);
11811193

11821194
let data_ptr = unwind_data.data_ptr.clone();

src/helpers.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<'
2727
for item in mem::replace(&mut items, Default::default()).iter() {
2828
if item.ident.name.as_str() == *segment {
2929
if path_it.peek().is_none() {
30-
return Some(ty::Instance::mono(this.tcx.tcx, item.res.def_id()).def_id());
30+
return Some(item.res.def_id())
31+
//eprintln!("Generics: {:?}", this.tcx.generics_of(item.res.def_id()));
32+
//return Some(ty::Instance::mono(this.tcx.tcx, item.res.def_id()).def_id());
3133
}
3234

3335
items = this.tcx.item_children(item.res.def_id());

src/lib.rs

+61-6
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,8 @@ pub struct Evaluator<'tcx> {
379379

380380
/// Whether or not we are currently unwinding from
381381
/// a panic
382-
pub(crate) unwinding: bool
382+
pub(crate) unwinding: bool,
383+
pub(crate) box_me_up_tmp_ptr: Option<MPlaceTy<'tcx, Tag>>
383384
}
384385

385386
pub struct CachedTypes<'tcx> {
@@ -399,7 +400,8 @@ impl<'tcx> Evaluator<'tcx> {
399400
validate,
400401
rng: seed.map(|s| StdRng::seed_from_u64(s)),
401402
cached_data: None,
402-
unwinding: false
403+
unwinding: false,
404+
box_me_up_tmp_ptr: None
403405
}
404406
}
405407
}
@@ -426,7 +428,8 @@ impl<'a, 'mir, 'tcx> MiriEvalContextExt<'a, 'mir, 'tcx> for MiriEvalContext<'a,
426428

427429
pub struct FrameData<'tcx> {
428430
pub call_id: stacked_borrows::CallId,
429-
pub catch_panic: Option<UnwindData<'tcx>>
431+
pub catch_panic: Option<UnwindData<'tcx>>,
432+
pub is_box_me_frame: bool
430433
}
431434

432435
/// Hold all of the relevant data for a call to
@@ -439,7 +442,7 @@ pub struct UnwindData<'tcx> {
439442
pub data_ptr: MPlaceTy<'tcx, Tag>,
440443
pub vtable_ptr: MPlaceTy<'tcx, Tag>,
441444
pub dest: PlaceTy<'tcx, Tag>,
442-
pub ret: mir::BasicBlock
445+
pub ret: mir::BasicBlock,
443446
}
444447

445448
impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> {
@@ -467,8 +470,9 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> {
467470
args: &[OpTy<'tcx, Tag>],
468471
dest: Option<PlaceTy<'tcx, Tag>>,
469472
ret: Option<mir::BasicBlock>,
473+
unwind: Option<mir::BasicBlock>
470474
) -> EvalResult<'tcx, Option<&'mir mir::Mir<'tcx>>> {
471-
ecx.find_fn(instance, args, dest, ret)
475+
ecx.find_fn(instance, args, dest, ret, unwind)
472476
}
473477

474478
#[inline(always)]
@@ -633,7 +637,8 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> {
633637
) -> EvalResult<'tcx, FrameData<'tcx>> {
634638
Ok(FrameData {
635639
call_id: ecx.memory().extra.borrow_mut().new_call(),
636-
catch_panic: None
640+
catch_panic: None,
641+
is_box_me_frame: false
637642
})
638643
}
639644

@@ -642,6 +647,56 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> {
642647
ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>,
643648
extra: FrameData,
644649
) -> EvalResult<'tcx, StackPopInfo> {
650+
if extra.is_box_me_frame {
651+
trace!("unwinding: found box_me_frame");
652+
ecx.machine.unwinding = true;
653+
}
654+
if ecx.machine.unwinding {
655+
trace!("Popping during unwind!");
656+
if let Some(unwind_data) = ecx.frame_mut().extra.catch_panic.take() {
657+
// We've just popped the frame that was immediately above
658+
// our target frame on the stack.
659+
//
660+
trace!("unwinding: found target frame: {:?}", ecx.frame().span);
661+
662+
// 'box_me_up' has finished. 'temp_ptr' now holds
663+
// a '*mut (dyn Any + Send)'
664+
// We want to split this into its consituient parts -
665+
// the data and vtable pointers - and store them back
666+
// into the panic handler frame
667+
let tmp_ptr = ecx.machine.box_me_up_tmp_ptr.take().unwrap();
668+
let real_ret = ecx.read_immediate(tmp_ptr.into())?;
669+
let payload_data_ptr = real_ret.to_scalar_ptr()?;
670+
let payload_vtable_ptr = real_ret.to_meta()?.expect("Expected fat pointer");
671+
672+
673+
let data_ptr = unwind_data.data_ptr.clone();
674+
let vtable_ptr = unwind_data.vtable_ptr.clone();
675+
let dest = unwind_data.dest.clone();
676+
let ret = unwind_data.ret.clone();
677+
drop(unwind_data);
678+
679+
680+
// Here, we write directly into the frame of the function
681+
// that called '__rust_maybe_catch_panic'.
682+
// (NOT the function that called '__rust_start_panic')
683+
684+
ecx.write_scalar(payload_data_ptr, data_ptr.into())?;
685+
ecx.write_scalar(payload_vtable_ptr, vtable_ptr.into())?;
686+
687+
// We 'return' the value 1 from __rust_maybe_catch_panic,
688+
// since there was a panic
689+
ecx.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?;
690+
ecx.machine.unwinding = false;
691+
692+
ecx.memory_mut().deallocate(tmp_ptr.to_ptr()?, None, MiriMemoryKind::UnwindHelper.into())?;
693+
694+
// We're done - continue execution in the frame of the function
695+
// that called '__rust_maybe_catch_panic,'
696+
//this.goto_block(Some(ret))?;
697+
698+
}
699+
}
645700
ecx.memory().extra.borrow_mut().end_call(extra.call_id);
646701
Ok(StackPopInfo { unwinding: ecx.machine.unwinding })
647702
}

0 commit comments

Comments
 (0)