Skip to content
Permalink
Browse files

Miri: add machine hook for MIR-level assertion panics

  • Loading branch information
RalfJung committed Nov 29, 2019
1 parent f5c81e0 commit b1aa3cac5b7f5ac3e527f32431fa82e1c7d00c52
@@ -23,7 +23,7 @@ use syntax::{source_map::{Span, DUMMY_SP}, symbol::Symbol};
use crate::interpret::{self,
PlaceTy, MPlaceTy, OpTy, ImmTy, Immediate, Scalar, Pointer,
RawConst, ConstValue, Machine,
InterpResult, InterpErrorInfo, GlobalId, InterpCx, StackPopCleanup,
InterpResult, InterpErrorInfo, GlobalId, InterpCx, StackPopCleanup, AssertMessage,
Allocation, AllocId, MemoryKind, Memory,
snapshot, RefTracking, intern_const_alloc_recursive,
};
@@ -395,6 +395,39 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
)
}

fn assert_panic(
ecx: &mut InterpCx<'mir, 'tcx, Self>,
msg: &AssertMessage<'tcx>,
_unwind: Option<mir::BasicBlock>,
) -> InterpResult<'tcx> {
use rustc::mir::interpret::PanicInfo::*;
Err(match msg {
BoundsCheck { ref len, ref index } => {
let len = ecx
.read_immediate(ecx.eval_operand(len, None)?)
.expect("can't eval len")
.to_scalar()?
.to_machine_usize(&*ecx)?;
let index = ecx
.read_immediate(ecx.eval_operand(index, None)?)
.expect("can't eval index")
.to_scalar()?
.to_machine_usize(&*ecx)?;
err_panic!(BoundsCheck { len, index })
}
Overflow(op) => err_panic!(Overflow(*op)),
OverflowNeg => err_panic!(OverflowNeg),
DivisionByZero => err_panic!(DivisionByZero),
RemainderByZero => err_panic!(RemainderByZero),
ResumedAfterReturn(generator_kind)
=> err_panic!(ResumedAfterReturn(*generator_kind)),
ResumedAfterPanic(generator_kind)
=> err_panic!(ResumedAfterPanic(*generator_kind)),
Panic { .. } => bug!("`Panic` variant cannot occur in MIR"),
}
.into())
}

fn ptr_to_int(
_mem: &Memory<'mir, 'tcx, Self>,
_ptr: Pointer,
@@ -11,7 +11,7 @@ use rustc::ty::{self, Ty, TyCtxt};
use syntax_pos::Span;

use super::{
Allocation, AllocId, InterpResult, Scalar, AllocationExtra,
Allocation, AllocId, InterpResult, Scalar, AllocationExtra, AssertMessage,
InterpCx, PlaceTy, OpTy, ImmTy, MemoryKind, Pointer, Memory,
Frame, Operand,
};
@@ -175,6 +175,13 @@ pub trait Machine<'mir, 'tcx>: Sized {
unwind: Option<mir::BasicBlock>,
) -> InterpResult<'tcx>;

/// Called to evaluate `Assert` MIR terminators that trigger a panic.
fn assert_panic(
ecx: &mut InterpCx<'mir, 'tcx, Self>,
msg: &AssertMessage<'tcx>,
unwind: Option<mir::BasicBlock>,
) -> InterpResult<'tcx>;

/// Called for read access to a foreign static item.
///
/// This will only be called once per static and machine; the result is cached in
@@ -7,8 +7,8 @@ use syntax::source_map::Span;
use rustc_target::spec::abi::Abi;

use super::{
GlobalId, InterpResult, PointerArithmetic,
InterpCx, Machine, OpTy, ImmTy, PlaceTy, MPlaceTy, StackPopCleanup, FnVal,
GlobalId, InterpResult, InterpCx, Machine,
OpTy, ImmTy, PlaceTy, MPlaceTy, StackPopCleanup, FnVal,
};

impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
@@ -115,40 +115,14 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
expected,
ref msg,
target,
..
cleanup,
} => {
let cond_val = self.read_immediate(self.eval_operand(cond, None)?)?
.to_scalar()?.to_bool()?;
if expected == cond_val {
self.go_to_block(target);
} else {
// Compute error message
use rustc::mir::interpret::PanicInfo::*;
return Err(match msg {
BoundsCheck { ref len, ref index } => {
let len = self
.read_immediate(self.eval_operand(len, None)?)
.expect("can't eval len")
.to_scalar()?
.to_bits(self.memory.pointer_size())? as u64;
let index = self
.read_immediate(self.eval_operand(index, None)?)
.expect("can't eval index")
.to_scalar()?
.to_bits(self.memory.pointer_size())? as u64;
err_panic!(BoundsCheck { len, index })
}
Overflow(op) => err_panic!(Overflow(*op)),
OverflowNeg => err_panic!(OverflowNeg),
DivisionByZero => err_panic!(DivisionByZero),
RemainderByZero => err_panic!(RemainderByZero),
ResumedAfterReturn(generator_kind)
=> err_panic!(ResumedAfterReturn(*generator_kind)),
ResumedAfterPanic(generator_kind)
=> err_panic!(ResumedAfterPanic(*generator_kind)),
Panic { .. } => bug!("`Panic` variant cannot occur in MIR"),
}
.into());
M::assert_panic(self, msg, cleanup)?;
}
}

@@ -164,15 +138,21 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
return Ok(())
},

// It is UB to ever encounter this.
Unreachable => throw_ub!(Unreachable),

// These should never occur for MIR we actually run.
DropAndReplace { .. } |
FalseEdges { .. } |
FalseUnwind { .. } =>
bug!("{:#?} should have been eliminated by MIR pass", terminator.kind),

// These are not (yet) supported. It is unclear if they even can occur in
// MIR that we actually run.
Yield { .. } |
GeneratorDrop |
DropAndReplace { .. } |
Abort => unimplemented!("{:#?}", terminator.kind),
FalseEdges { .. } => bug!("should have been eliminated by\
`simplify_branches` mir pass"),
FalseUnwind { .. } => bug!("should have been eliminated by\
`simplify_branches` mir pass"),
Unreachable => throw_ub!(Unreachable),
Abort =>
throw_unsup_format!("Unsupported terminator kind: {:#?}", terminator.kind),
}

Ok(())
@@ -156,6 +156,14 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine {
throw_unsup!(ConstPropUnsupported("calling intrinsics isn't supported in ConstProp"));
}

fn assert_panic(
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
_msg: &rustc::mir::interpret::AssertMessage<'tcx>,
_unwind: Option<rustc::mir::BasicBlock>,
) -> InterpResult<'tcx> {
throw_unsup_format!("panics are not supported in ConstProp");
}

fn ptr_to_int(
_mem: &Memory<'mir, 'tcx, Self>,
_ptr: Pointer,

0 comments on commit b1aa3ca

Please sign in to comment.
You can’t perform that action at this time.