Skip to content

Commit

Permalink
Use a machine error to catch tag destruction and continue interpretat…
Browse files Browse the repository at this point in the history
…ion afterwards
  • Loading branch information
oli-obk committed Dec 8, 2019
1 parent 7cd0d7f commit d6f168a
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 39 deletions.
88 changes: 55 additions & 33 deletions src/eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,21 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) ->

// Perform the main execution.
let res: InterpResult<'_, i64> = (|| {
ecx.run()?;
loop {
match ecx.run() {
Ok(()) => break,
Err(e) => match &e.kind {
InterpError::MachineStop(f) => match f.downcast_ref::<PoppedTrackedPointer>() {
Some(ptp) => {
let msg = format!("Popped {:?} from borrow stack", ptp.item);
report_error(&ecx, e, msg);
},
None => return Err(e),
},
_ => return Err(e),
}
}
}
// Read the return code pointer *before* we run TLS destructors, to assert
// that it was written to by the time that `start` lang item returned.
let return_code = ecx.read_scalar(ret_place.into())?.not_undef()?.to_machine_isize(&ecx)?;
Expand All @@ -210,7 +224,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) ->
}
return Some(return_code)
}
Err(mut e) => {
Err(e) => {
// Special treatment for some error kinds
let msg = match e.kind {
InterpError::MachineStop(ref info) => {
Expand All @@ -228,41 +242,49 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) ->
bug!("This error should be impossible in Miri: {}", e),
_ => e.to_string()
};
e.print_backtrace();
if let Some(frame) = ecx.stack().last() {
let span = frame.current_source_info().unwrap().span;
report_error(&ecx, e, msg);
// Let the reported error determine the return code.
return None;
},
}
}

let msg = format!("Miri evaluation error: {}", msg);
let mut err = ecx.tcx.sess.struct_span_err(span, msg.as_str());
let frames = ecx.generate_stacktrace(None);
err.span_label(span, msg);
// We iterate with indices because we need to look at the next frame (the caller).
for idx in 0..frames.len() {
let frame_info = &frames[idx];
let call_site_is_local = frames.get(idx + 1).map_or(false, |caller_info| {
caller_info.instance.def_id().is_local()
});
if call_site_is_local {
err.span_note(frame_info.call_site, &frame_info.to_string());
} else {
err.note(&frame_info.to_string());
}
}
err.emit();
fn report_error<'mir, 'tcx>(
ecx: &InterpCx<'mir, 'tcx, Evaluator<'tcx>>,
mut e: InterpErrorInfo<'tcx>,
msg: String,
) {
e.print_backtrace();
if let Some(frame) = ecx.stack().last() {
let span = frame.current_source_info().unwrap().span;

let msg = format!("Miri evaluation error: {}", msg);
let mut err = ecx.tcx.sess.struct_span_err(span, msg.as_str());
let frames = ecx.generate_stacktrace(None);
err.span_label(span, msg);
// We iterate with indices because we need to look at the next frame (the caller).
for idx in 0..frames.len() {
let frame_info = &frames[idx];
let call_site_is_local = frames.get(idx + 1).map_or(false, |caller_info| {
caller_info.instance.def_id().is_local()
});
if call_site_is_local {
err.span_note(frame_info.call_site, &frame_info.to_string());
} else {
ecx.tcx.sess.err(&msg);
err.note(&frame_info.to_string());
}
}
err.emit();
} else {
ecx.tcx.sess.err(&msg);
}

for (i, frame) in ecx.stack().iter().enumerate() {
trace!("-------------------");
trace!("Frame {}", i);
trace!(" return: {:?}", frame.return_place.map(|p| *p));
for (i, local) in frame.locals.iter().enumerate() {
trace!(" local {}: {:?}", i, local.value);
}
}
// Let the reported error determine the return code.
return None;
for (i, frame) in ecx.stack().iter().enumerate() {
trace!("-------------------");
trace!("Frame {}", i);
trace!(" return: {:?}", frame.return_place.map(|p| *p));
for (i, local) in frame.locals.iter().enumerate() {
trace!(" local {}: {:?}", i, local.value);
}
}
}
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ pub use crate::helpers::{EvalContextExt as HelpersEvalContextExt};
pub use crate::mono_hash_map::MonoHashMap;
pub use crate::stacked_borrows::{
EvalContextExt as StackedBorEvalContextExt, Tag, Permission, Stack, Stacks, Item, PtrId,
GlobalState,
GlobalState, PoppedTrackedPointer
};
pub use crate::machine::{
PAGE_SIZE, STACK_ADDR, STACK_SIZE, NUM_CPUS,
Expand Down
15 changes: 10 additions & 5 deletions src/stacked_borrows.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Implements "Stacked Borrows". See <https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md>
//! for further information.
use std::cell::RefCell;
use std::cell::{Cell, RefCell};
use std::collections::{HashMap, HashSet};
use std::rc::Rc;
use std::fmt;
Expand Down Expand Up @@ -106,11 +106,15 @@ pub struct GlobalState {
/// Those call IDs corresponding to functions that are still running.
active_calls: HashSet<CallId>,
/// The id to trace in this execution run
tracked_pointer_tag: Option<PtrId>,
tracked_pointer_tag: Cell<Option<PtrId>>,
}
/// Memory extra state gives us interior mutable access to the global state.
pub type MemoryExtra = Rc<RefCell<GlobalState>>;

pub struct PoppedTrackedPointer {
pub item: Item,
}

/// Indicates which kind of access is being performed.
#[derive(Copy, Clone, Hash, PartialEq, Eq)]
pub enum AccessKind {
Expand Down Expand Up @@ -160,7 +164,7 @@ impl GlobalState {
base_ptr_ids: HashMap::default(),
next_call_id: NonZeroU64::new(1).unwrap(),
active_calls: HashSet::default(),
tracked_pointer_tag,
tracked_pointer_tag: Cell::new(tracked_pointer_tag),
}
}

Expand Down Expand Up @@ -272,8 +276,9 @@ impl<'tcx> Stack {
/// Check if the given item is protected.
fn check_protector(item: &Item, tag: Option<Tag>, global: &GlobalState) -> InterpResult<'tcx> {
if let Tag::Tagged(id) = item.tag {
if Some(id) == global.tracked_pointer_tag {
throw_unsup!(Unsupported(format!("disabling item {:?} for tag {:?}", item, tag)));
if Some(id) == global.tracked_pointer_tag.get() {
global.tracked_pointer_tag.set(None);
throw_machine_stop!(PoppedTrackedPointer { item: item.clone() });
}
}
if let Some(call) = item.protector {
Expand Down

0 comments on commit d6f168a

Please sign in to comment.