Skip to content

Commit b1aa3ca

Browse files
committed
Miri: add machine hook for MIR-level assertion panics
1 parent f5c81e0 commit b1aa3ca

File tree

4 files changed

+67
-39
lines changed

4 files changed

+67
-39
lines changed

src/librustc_mir/const_eval.rs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use syntax::{source_map::{Span, DUMMY_SP}, symbol::Symbol};
2323
use crate::interpret::{self,
2424
PlaceTy, MPlaceTy, OpTy, ImmTy, Immediate, Scalar, Pointer,
2525
RawConst, ConstValue, Machine,
26-
InterpResult, InterpErrorInfo, GlobalId, InterpCx, StackPopCleanup,
26+
InterpResult, InterpErrorInfo, GlobalId, InterpCx, StackPopCleanup, AssertMessage,
2727
Allocation, AllocId, MemoryKind, Memory,
2828
snapshot, RefTracking, intern_const_alloc_recursive,
2929
};
@@ -395,6 +395,39 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
395395
)
396396
}
397397

398+
fn assert_panic(
399+
ecx: &mut InterpCx<'mir, 'tcx, Self>,
400+
msg: &AssertMessage<'tcx>,
401+
_unwind: Option<mir::BasicBlock>,
402+
) -> InterpResult<'tcx> {
403+
use rustc::mir::interpret::PanicInfo::*;
404+
Err(match msg {
405+
BoundsCheck { ref len, ref index } => {
406+
let len = ecx
407+
.read_immediate(ecx.eval_operand(len, None)?)
408+
.expect("can't eval len")
409+
.to_scalar()?
410+
.to_machine_usize(&*ecx)?;
411+
let index = ecx
412+
.read_immediate(ecx.eval_operand(index, None)?)
413+
.expect("can't eval index")
414+
.to_scalar()?
415+
.to_machine_usize(&*ecx)?;
416+
err_panic!(BoundsCheck { len, index })
417+
}
418+
Overflow(op) => err_panic!(Overflow(*op)),
419+
OverflowNeg => err_panic!(OverflowNeg),
420+
DivisionByZero => err_panic!(DivisionByZero),
421+
RemainderByZero => err_panic!(RemainderByZero),
422+
ResumedAfterReturn(generator_kind)
423+
=> err_panic!(ResumedAfterReturn(*generator_kind)),
424+
ResumedAfterPanic(generator_kind)
425+
=> err_panic!(ResumedAfterPanic(*generator_kind)),
426+
Panic { .. } => bug!("`Panic` variant cannot occur in MIR"),
427+
}
428+
.into())
429+
}
430+
398431
fn ptr_to_int(
399432
_mem: &Memory<'mir, 'tcx, Self>,
400433
_ptr: Pointer,

src/librustc_mir/interpret/machine.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use rustc::ty::{self, Ty, TyCtxt};
1111
use syntax_pos::Span;
1212

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

178+
/// Called to evaluate `Assert` MIR terminators that trigger a panic.
179+
fn assert_panic(
180+
ecx: &mut InterpCx<'mir, 'tcx, Self>,
181+
msg: &AssertMessage<'tcx>,
182+
unwind: Option<mir::BasicBlock>,
183+
) -> InterpResult<'tcx>;
184+
178185
/// Called for read access to a foreign static item.
179186
///
180187
/// This will only be called once per static and machine; the result is cached in

src/librustc_mir/interpret/terminator.rs

Lines changed: 17 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ use syntax::source_map::Span;
77
use rustc_target::spec::abi::Abi;
88

99
use super::{
10-
GlobalId, InterpResult, PointerArithmetic,
11-
InterpCx, Machine, OpTy, ImmTy, PlaceTy, MPlaceTy, StackPopCleanup, FnVal,
10+
GlobalId, InterpResult, InterpCx, Machine,
11+
OpTy, ImmTy, PlaceTy, MPlaceTy, StackPopCleanup, FnVal,
1212
};
1313

1414
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> {
115115
expected,
116116
ref msg,
117117
target,
118-
..
118+
cleanup,
119119
} => {
120120
let cond_val = self.read_immediate(self.eval_operand(cond, None)?)?
121121
.to_scalar()?.to_bool()?;
122122
if expected == cond_val {
123123
self.go_to_block(target);
124124
} else {
125-
// Compute error message
126-
use rustc::mir::interpret::PanicInfo::*;
127-
return Err(match msg {
128-
BoundsCheck { ref len, ref index } => {
129-
let len = self
130-
.read_immediate(self.eval_operand(len, None)?)
131-
.expect("can't eval len")
132-
.to_scalar()?
133-
.to_bits(self.memory.pointer_size())? as u64;
134-
let index = self
135-
.read_immediate(self.eval_operand(index, None)?)
136-
.expect("can't eval index")
137-
.to_scalar()?
138-
.to_bits(self.memory.pointer_size())? as u64;
139-
err_panic!(BoundsCheck { len, index })
140-
}
141-
Overflow(op) => err_panic!(Overflow(*op)),
142-
OverflowNeg => err_panic!(OverflowNeg),
143-
DivisionByZero => err_panic!(DivisionByZero),
144-
RemainderByZero => err_panic!(RemainderByZero),
145-
ResumedAfterReturn(generator_kind)
146-
=> err_panic!(ResumedAfterReturn(*generator_kind)),
147-
ResumedAfterPanic(generator_kind)
148-
=> err_panic!(ResumedAfterPanic(*generator_kind)),
149-
Panic { .. } => bug!("`Panic` variant cannot occur in MIR"),
150-
}
151-
.into());
125+
M::assert_panic(self, msg, cleanup)?;
152126
}
153127
}
154128

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

141+
// It is UB to ever encounter this.
142+
Unreachable => throw_ub!(Unreachable),
143+
144+
// These should never occur for MIR we actually run.
145+
DropAndReplace { .. } |
146+
FalseEdges { .. } |
147+
FalseUnwind { .. } =>
148+
bug!("{:#?} should have been eliminated by MIR pass", terminator.kind),
149+
150+
// These are not (yet) supported. It is unclear if they even can occur in
151+
// MIR that we actually run.
167152
Yield { .. } |
168153
GeneratorDrop |
169-
DropAndReplace { .. } |
170-
Abort => unimplemented!("{:#?}", terminator.kind),
171-
FalseEdges { .. } => bug!("should have been eliminated by\
172-
`simplify_branches` mir pass"),
173-
FalseUnwind { .. } => bug!("should have been eliminated by\
174-
`simplify_branches` mir pass"),
175-
Unreachable => throw_ub!(Unreachable),
154+
Abort =>
155+
throw_unsup_format!("Unsupported terminator kind: {:#?}", terminator.kind),
176156
}
177157

178158
Ok(())

src/librustc_mir/transform/const_prop.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,14 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine {
156156
throw_unsup!(ConstPropUnsupported("calling intrinsics isn't supported in ConstProp"));
157157
}
158158

159+
fn assert_panic(
160+
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
161+
_msg: &rustc::mir::interpret::AssertMessage<'tcx>,
162+
_unwind: Option<rustc::mir::BasicBlock>,
163+
) -> InterpResult<'tcx> {
164+
throw_unsup_format!("panics are not supported in ConstProp");
165+
}
166+
159167
fn ptr_to_int(
160168
_mem: &Memory<'mir, 'tcx, Self>,
161169
_ptr: Pointer,

0 commit comments

Comments
 (0)