blob: 85564e47685f2b64ee7472fc78ffadce1fbbc663 [file] [log] [blame] [edit]
//! Helper functions for causing panics.
use rustc_abi::ExternAbi;
use rustc_middle::{mir, ty};
use crate::*;
impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
/// Start a panic in the interpreter with the given message as payload.
fn start_panic(&mut self, msg: &str, unwind: mir::UnwindAction) -> InterpResult<'tcx> {
let this = self.eval_context_mut();
// First arg: message.
let msg = this.allocate_str_dedup(msg)?;
// Call the lang item.
let panic = this.tcx.lang_items().panic_fn().unwrap();
let panic = ty::Instance::mono(this.tcx.tcx, panic);
this.call_function(
panic,
ExternAbi::Rust,
&[this.mplace_to_ref(&msg)?],
None,
ReturnContinuation::Goto { ret: None, unwind },
)
}
/// Start a non-unwinding panic in the interpreter with the given message as payload.
fn start_panic_nounwind(&mut self, msg: &str) -> InterpResult<'tcx> {
let this = self.eval_context_mut();
// First arg: message.
let msg = this.allocate_str_dedup(msg)?;
// Call the lang item.
let panic = this.tcx.lang_items().panic_nounwind().unwrap();
let panic = ty::Instance::mono(this.tcx.tcx, panic);
this.call_function(
panic,
ExternAbi::Rust,
&[this.mplace_to_ref(&msg)?],
None,
ReturnContinuation::Goto { ret: None, unwind: mir::UnwindAction::Unreachable },
)
}
fn assert_panic(
&mut self,
msg: &mir::AssertMessage<'tcx>,
unwind: mir::UnwindAction,
) -> InterpResult<'tcx> {
use rustc_middle::mir::AssertKind::*;
let this = self.eval_context_mut();
match msg {
BoundsCheck { index, len } => {
// Forward to `panic_bounds_check` lang item.
// First arg: index.
let index = this.read_immediate(&this.eval_operand(index, None)?)?;
// Second arg: len.
let len = this.read_immediate(&this.eval_operand(len, None)?)?;
// Call the lang item.
let panic_bounds_check = this.tcx.lang_items().panic_bounds_check_fn().unwrap();
let panic_bounds_check = ty::Instance::mono(this.tcx.tcx, panic_bounds_check);
this.call_function(
panic_bounds_check,
ExternAbi::Rust,
&[index, len],
None,
ReturnContinuation::Goto { ret: None, unwind },
)?;
}
MisalignedPointerDereference { required, found } => {
// Forward to `panic_misaligned_pointer_dereference` lang item.
// First arg: required.
let required = this.read_immediate(&this.eval_operand(required, None)?)?;
// Second arg: found.
let found = this.read_immediate(&this.eval_operand(found, None)?)?;
// Call the lang item.
let panic_misaligned_pointer_dereference =
this.tcx.lang_items().panic_misaligned_pointer_dereference_fn().unwrap();
let panic_misaligned_pointer_dereference =
ty::Instance::mono(this.tcx.tcx, panic_misaligned_pointer_dereference);
this.call_function(
panic_misaligned_pointer_dereference,
ExternAbi::Rust,
&[required, found],
None,
ReturnContinuation::Goto { ret: None, unwind },
)?;
}
_ => {
// Call the lang item associated with this message.
let fn_item = this.tcx.require_lang_item(msg.panic_function(), this.tcx.span);
let instance = ty::Instance::mono(this.tcx.tcx, fn_item);
this.call_function(
instance,
ExternAbi::Rust,
&[],
None,
ReturnContinuation::Goto { ret: None, unwind },
)?;
}
}
interp_ok(())
}
}