miri/shims/
panic.rs

1//! Helper functions for causing panics.
2
3use rustc_abi::ExternAbi;
4use rustc_middle::{mir, ty};
5
6use crate::*;
7
8impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
9pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
10    /// Start a panic in the interpreter with the given message as payload.
11    fn start_panic(&mut self, msg: &str, unwind: mir::UnwindAction) -> InterpResult<'tcx> {
12        let this = self.eval_context_mut();
13
14        // First arg: message.
15        let msg = this.allocate_str_dedup(msg)?;
16
17        // Call the lang item.
18        let panic = this.tcx.lang_items().panic_fn().unwrap();
19        let panic = ty::Instance::mono(this.tcx.tcx, panic);
20        this.call_function(
21            panic,
22            ExternAbi::Rust,
23            &[this.mplace_to_ref(&msg)?],
24            None,
25            ReturnContinuation::Goto { ret: None, unwind },
26        )
27    }
28
29    /// Start a non-unwinding panic in the interpreter with the given message as payload.
30    fn start_panic_nounwind(&mut self, msg: &str) -> InterpResult<'tcx> {
31        let this = self.eval_context_mut();
32
33        // First arg: message.
34        let msg = this.allocate_str_dedup(msg)?;
35
36        // Call the lang item.
37        let panic = this.tcx.lang_items().panic_nounwind().unwrap();
38        let panic = ty::Instance::mono(this.tcx.tcx, panic);
39        this.call_function(
40            panic,
41            ExternAbi::Rust,
42            &[this.mplace_to_ref(&msg)?],
43            None,
44            ReturnContinuation::Goto { ret: None, unwind: mir::UnwindAction::Unreachable },
45        )
46    }
47
48    fn assert_panic(
49        &mut self,
50        msg: &mir::AssertMessage<'tcx>,
51        unwind: mir::UnwindAction,
52    ) -> InterpResult<'tcx> {
53        use rustc_middle::mir::AssertKind::*;
54        let this = self.eval_context_mut();
55
56        match msg {
57            BoundsCheck { index, len } => {
58                // Forward to `panic_bounds_check` lang item.
59
60                // First arg: index.
61                let index = this.read_immediate(&this.eval_operand(index, None)?)?;
62                // Second arg: len.
63                let len = this.read_immediate(&this.eval_operand(len, None)?)?;
64
65                // Call the lang item.
66                let panic_bounds_check = this.tcx.lang_items().panic_bounds_check_fn().unwrap();
67                let panic_bounds_check = ty::Instance::mono(this.tcx.tcx, panic_bounds_check);
68                this.call_function(
69                    panic_bounds_check,
70                    ExternAbi::Rust,
71                    &[index, len],
72                    None,
73                    ReturnContinuation::Goto { ret: None, unwind },
74                )?;
75            }
76            MisalignedPointerDereference { required, found } => {
77                // Forward to `panic_misaligned_pointer_dereference` lang item.
78
79                // First arg: required.
80                let required = this.read_immediate(&this.eval_operand(required, None)?)?;
81                // Second arg: found.
82                let found = this.read_immediate(&this.eval_operand(found, None)?)?;
83
84                // Call the lang item.
85                let panic_misaligned_pointer_dereference =
86                    this.tcx.lang_items().panic_misaligned_pointer_dereference_fn().unwrap();
87                let panic_misaligned_pointer_dereference =
88                    ty::Instance::mono(this.tcx.tcx, panic_misaligned_pointer_dereference);
89                this.call_function(
90                    panic_misaligned_pointer_dereference,
91                    ExternAbi::Rust,
92                    &[required, found],
93                    None,
94                    ReturnContinuation::Goto { ret: None, unwind },
95                )?;
96            }
97
98            _ => {
99                // Call the lang item associated with this message.
100                let fn_item = this.tcx.require_lang_item(msg.panic_function(), this.tcx.span);
101                let instance = ty::Instance::mono(this.tcx.tcx, fn_item);
102                this.call_function(
103                    instance,
104                    ExternAbi::Rust,
105                    &[],
106                    None,
107                    ReturnContinuation::Goto { ret: None, unwind },
108                )?;
109            }
110        }
111        interp_ok(())
112    }
113}