1use std::fmt::{self, Write};
2use std::num::NonZero;
3
4use rustc_abi::{Align, Size};
5use rustc_errors::{Diag, DiagMessage, Level};
6use rustc_span::{DUMMY_SP, SpanData, Symbol};
7
8use crate::borrow_tracker::stacked_borrows::diagnostics::TagHistory;
9use crate::borrow_tracker::tree_borrows::diagnostics as tree_diagnostics;
10use crate::*;
11
12pub enum TerminationInfo {
14 Exit {
15 code: i32,
16 leak_check: bool,
17 },
18 Abort(String),
19 UnsupportedInIsolation(String),
20 StackedBorrowsUb {
21 msg: String,
22 help: Vec<String>,
23 history: Option<TagHistory>,
24 },
25 TreeBorrowsUb {
26 title: String,
27 details: Vec<String>,
28 history: tree_diagnostics::HistoryData,
29 },
30 Int2PtrWithStrictProvenance,
31 Deadlock,
32 MultipleSymbolDefinitions {
33 link_name: Symbol,
34 first: SpanData,
35 first_crate: Symbol,
36 second: SpanData,
37 second_crate: Symbol,
38 },
39 SymbolShimClashing {
40 link_name: Symbol,
41 span: SpanData,
42 },
43 DataRace {
44 involves_non_atomic: bool,
45 ptr: interpret::Pointer<AllocId>,
46 op1: RacingOp,
47 op2: RacingOp,
48 extra: Option<&'static str>,
49 retag_explain: bool,
50 },
51 UnsupportedForeignItem(String),
52}
53
54pub struct RacingOp {
55 pub action: String,
56 pub thread_info: String,
57 pub span: SpanData,
58}
59
60impl fmt::Display for TerminationInfo {
61 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62 use TerminationInfo::*;
63 match self {
64 Exit { code, .. } => write!(f, "the evaluated program completed with exit code {code}"),
65 Abort(msg) => write!(f, "{msg}"),
66 UnsupportedInIsolation(msg) => write!(f, "{msg}"),
67 Int2PtrWithStrictProvenance =>
68 write!(
69 f,
70 "integer-to-pointer casts and `ptr::with_exposed_provenance` are not supported with `-Zmiri-strict-provenance`"
71 ),
72 StackedBorrowsUb { msg, .. } => write!(f, "{msg}"),
73 TreeBorrowsUb { title, .. } => write!(f, "{title}"),
74 Deadlock => write!(f, "the evaluated program deadlocked"),
75 MultipleSymbolDefinitions { link_name, .. } =>
76 write!(f, "multiple definitions of symbol `{link_name}`"),
77 SymbolShimClashing { link_name, .. } =>
78 write!(f, "found `{link_name}` symbol definition that clashes with a built-in shim",),
79 DataRace { involves_non_atomic, ptr, op1, op2, .. } =>
80 write!(
81 f,
82 "{} detected between (1) {} on {} and (2) {} on {} at {ptr:?}. (2) just happened here",
83 if *involves_non_atomic { "Data race" } else { "Race condition" },
84 op1.action,
85 op1.thread_info,
86 op2.action,
87 op2.thread_info
88 ),
89 UnsupportedForeignItem(msg) => write!(f, "{msg}"),
90 }
91 }
92}
93
94impl fmt::Debug for TerminationInfo {
95 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
96 write!(f, "{self}")
97 }
98}
99
100impl MachineStopType for TerminationInfo {
101 fn diagnostic_message(&self) -> DiagMessage {
102 self.to_string().into()
103 }
104 fn add_args(
105 self: Box<Self>,
106 _: &mut dyn FnMut(std::borrow::Cow<'static, str>, rustc_errors::DiagArgValue),
107 ) {
108 }
109}
110
111pub enum NonHaltingDiagnostic {
113 CreatedPointerTag(NonZero<u64>, Option<String>, Option<(AllocId, AllocRange, ProvenanceExtra)>),
117 PoppedPointerTag(Item, String),
119 CreatedAlloc(AllocId, Size, Align, MemoryKind),
120 FreedAlloc(AllocId),
121 AccessedAlloc(AllocId, AccessKind),
122 RejectedIsolatedOp(String),
123 ProgressReport {
124 block_count: u64, },
126 Int2Ptr {
127 details: bool,
128 },
129 NativeCallSharedMem,
130 WeakMemoryOutdatedLoad {
131 ptr: Pointer,
132 },
133 ExternTypeReborrow,
134}
135
136pub enum DiagLevel {
138 Error,
139 Warning,
140 Note,
141}
142
143macro_rules! note {
145 ($($tt:tt)*) => { (None, format!($($tt)*)) };
146}
147macro_rules! note_span {
149 ($span:expr, $($tt:tt)*) => { (Some($span), format!($($tt)*)) };
150}
151
152pub fn prune_stacktrace<'tcx>(
156 mut stacktrace: Vec<FrameInfo<'tcx>>,
157 machine: &MiriMachine<'tcx>,
158) -> (Vec<FrameInfo<'tcx>>, bool) {
159 match machine.backtrace_style {
160 BacktraceStyle::Off => {
161 stacktrace.retain(|frame| !frame.instance.def.requires_caller_location(machine.tcx));
164 stacktrace.truncate(1);
166 (stacktrace, false)
167 }
168 BacktraceStyle::Short => {
169 let original_len = stacktrace.len();
170 let has_local_frame = stacktrace.iter().any(|frame| machine.is_local(frame));
174 if has_local_frame {
175 stacktrace
178 .retain(|frame| !frame.instance.def.requires_caller_location(machine.tcx));
179
180 stacktrace = stacktrace
185 .into_iter()
186 .take_while(|frame| {
187 let def_id = frame.instance.def_id();
188 let path = machine.tcx.def_path_str(def_id);
189 !path.contains("__rust_begin_short_backtrace")
190 })
191 .collect::<Vec<_>>();
192
193 while stacktrace.len() > 1
199 && stacktrace.last().is_some_and(|frame| !machine.is_local(frame))
200 {
201 stacktrace.pop();
202 }
203 }
204 let was_pruned = stacktrace.len() != original_len;
205 (stacktrace, was_pruned)
206 }
207 BacktraceStyle::Full => (stacktrace, false),
208 }
209}
210
211pub fn report_error<'tcx>(
215 ecx: &InterpCx<'tcx, MiriMachine<'tcx>>,
216 e: InterpErrorInfo<'tcx>,
217) -> Option<(i32, bool)> {
218 use InterpErrorKind::*;
219 use UndefinedBehaviorInfo::*;
220
221 let mut msg = vec![];
222
223 let (title, helps) = if let MachineStop(info) = e.kind() {
224 let info = info.downcast_ref::<TerminationInfo>().expect("invalid MachineStop payload");
225 use TerminationInfo::*;
226 let title = match info {
227 &Exit { code, leak_check } => return Some((code, leak_check)),
228 Abort(_) => Some("abnormal termination"),
229 UnsupportedInIsolation(_) | Int2PtrWithStrictProvenance | UnsupportedForeignItem(_) =>
230 Some("unsupported operation"),
231 StackedBorrowsUb { .. } | TreeBorrowsUb { .. } | DataRace { .. } =>
232 Some("Undefined Behavior"),
233 Deadlock => Some("deadlock"),
234 MultipleSymbolDefinitions { .. } | SymbolShimClashing { .. } => None,
235 };
236 #[rustfmt::skip]
237 let helps = match info {
238 UnsupportedInIsolation(_) =>
239 vec![
240 note!("set `MIRIFLAGS=-Zmiri-disable-isolation` to disable isolation;"),
241 note!("or set `MIRIFLAGS=-Zmiri-isolation-error=warn` to make Miri return an error code from isolated operations (if supported for that operation) and continue with a warning"),
242 ],
243 UnsupportedForeignItem(_) => {
244 vec![
245 note!("if this is a basic API commonly used on this target, please report an issue with Miri"),
246 note!("however, note that Miri does not aim to support every FFI function out there; for instance, we will not support APIs for things such as GUIs, scripting languages, or databases"),
247 ]
248 }
249 StackedBorrowsUb { help, history, .. } => {
250 msg.extend(help.clone());
251 let mut helps = vec![
252 note!("this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental"),
253 note!("see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information"),
254 ];
255 if let Some(TagHistory {created, invalidated, protected}) = history.clone() {
256 helps.push((Some(created.1), created.0));
257 if let Some((msg, span)) = invalidated {
258 helps.push(note_span!(span, "{msg}"));
259 }
260 if let Some((protector_msg, protector_span)) = protected {
261 helps.push(note_span!(protector_span, "{protector_msg}"));
262 }
263 }
264 helps
265 },
266 TreeBorrowsUb { title: _, details, history } => {
267 let mut helps = vec![
268 note!("this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental")
269 ];
270 for m in details {
271 helps.push(note!("{m}"));
272 }
273 for event in history.events.clone() {
274 helps.push(event);
275 }
276 helps
277 }
278 MultipleSymbolDefinitions { first, first_crate, second, second_crate, .. } =>
279 vec![
280 note_span!(*first, "it's first defined here, in crate `{first_crate}`"),
281 note_span!(*second, "then it's defined here again, in crate `{second_crate}`"),
282 ],
283 SymbolShimClashing { link_name, span } =>
284 vec![note_span!(*span, "the `{link_name}` symbol is defined here")],
285 Int2PtrWithStrictProvenance =>
286 vec![note!("use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead")],
287 DataRace { op1, extra, retag_explain, .. } => {
288 let mut helps = vec![note_span!(op1.span, "and (1) occurred earlier here")];
289 if let Some(extra) = extra {
290 helps.push(note!("{extra}"));
291 helps.push(note!("see https://doc.rust-lang.org/nightly/std/sync/atomic/index.html#memory-model-for-atomic-accesses for more information about the Rust memory model"));
292 }
293 if *retag_explain {
294 helps.push(note!("retags occur on all (re)borrows and as well as when references are copied or moved"));
295 helps.push(note!("retags permit optimizations that insert speculative reads or writes"));
296 helps.push(note!("therefore from the perspective of data races, a retag has the same implications as a read or write"));
297 }
298 helps.push(note!("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior"));
299 helps.push(note!("see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information"));
300 helps
301 }
302 ,
303 _ => vec![],
304 };
305 (title, helps)
306 } else {
307 let title = match e.kind() {
308 UndefinedBehavior(ValidationError(validation_err))
309 if matches!(
310 validation_err.kind,
311 ValidationErrorKind::PointerAsInt { .. } | ValidationErrorKind::PartialPointer
312 ) =>
313 {
314 ecx.handle_ice(); bug!(
316 "This validation error should be impossible in Miri: {}",
317 format_interp_error(ecx.tcx.dcx(), e)
318 );
319 }
320 UndefinedBehavior(_) => "Undefined Behavior",
321 ResourceExhaustion(_) => "resource exhaustion",
322 Unsupported(
323 UnsupportedOpInfo::Unsupported(_)
325 | UnsupportedOpInfo::UnsizedLocal
326 | UnsupportedOpInfo::ExternTypeField,
327 ) => "unsupported operation",
328 InvalidProgram(
329 InvalidProgramInfo::AlreadyReported(_) | InvalidProgramInfo::Layout(..),
331 ) => "post-monomorphization error",
332 _ => {
333 ecx.handle_ice(); bug!(
335 "This error should be impossible in Miri: {}",
336 format_interp_error(ecx.tcx.dcx(), e)
337 );
338 }
339 };
340 #[rustfmt::skip]
341 let helps = match e.kind() {
342 Unsupported(_) =>
343 vec![
344 note!("this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support"),
345 ],
346 UndefinedBehavior(AlignmentCheckFailed { .. })
347 if ecx.machine.check_alignment == AlignmentCheck::Symbolic
348 =>
349 vec![
350 note!("this usually indicates that your program performed an invalid operation and caused Undefined Behavior"),
351 note!("but due to `-Zmiri-symbolic-alignment-check`, alignment errors can also be false positives"),
352 ],
353 UndefinedBehavior(info) => {
354 let mut helps = vec![
355 note!("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior"),
356 note!("see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information"),
357 ];
358 match info {
359 PointerUseAfterFree(alloc_id, _) | PointerOutOfBounds { alloc_id, .. } => {
360 if let Some(span) = ecx.machine.allocated_span(*alloc_id) {
361 helps.push(note_span!(span, "{:?} was allocated here:", alloc_id));
362 }
363 if let Some(span) = ecx.machine.deallocated_span(*alloc_id) {
364 helps.push(note_span!(span, "{:?} was deallocated here:", alloc_id));
365 }
366 }
367 AbiMismatchArgument { .. } | AbiMismatchReturn { .. } => {
368 helps.push(note!("this means these two types are not *guaranteed* to be ABI-compatible across all targets"));
369 helps.push(note!("if you think this code should be accepted anyway, please report an issue with Miri"));
370 }
371 _ => {},
372 }
373 helps
374 }
375 InvalidProgram(
376 InvalidProgramInfo::AlreadyReported(_)
377 ) => {
378 return None;
380 }
381 _ =>
382 vec![],
383 };
384 (Some(title), helps)
385 };
386
387 let stacktrace = ecx.generate_stacktrace();
388 let (stacktrace, mut any_pruned) = prune_stacktrace(stacktrace, &ecx.machine);
389
390 let mut show_all_threads = false;
391
392 let mut extra = String::new();
395 match e.kind() {
396 UndefinedBehavior(InvalidUninitBytes(Some((alloc_id, access)))) => {
397 writeln!(
398 extra,
399 "Uninitialized memory occurred at {alloc_id:?}{range:?}, in this allocation:",
400 range = access.bad,
401 )
402 .unwrap();
403 writeln!(extra, "{:?}", ecx.dump_alloc(*alloc_id)).unwrap();
404 }
405 MachineStop(info) => {
406 let info = info.downcast_ref::<TerminationInfo>().expect("invalid MachineStop payload");
407 match info {
408 TerminationInfo::Deadlock => {
409 show_all_threads = true;
410 }
411 _ => {}
412 }
413 }
414 _ => {}
415 }
416
417 msg.insert(0, format_interp_error(ecx.tcx.dcx(), e));
418
419 report_msg(
420 DiagLevel::Error,
421 if let Some(title) = title { format!("{title}: {}", msg[0]) } else { msg[0].clone() },
422 msg,
423 vec![],
424 helps,
425 &stacktrace,
426 Some(ecx.active_thread()),
427 &ecx.machine,
428 );
429
430 eprint!("{extra}"); if show_all_threads {
433 for (thread, stack) in ecx.machine.threads.all_stacks() {
434 if thread != ecx.active_thread() {
435 let stacktrace = Frame::generate_stacktrace_from_stack(stack);
436 let (stacktrace, was_pruned) = prune_stacktrace(stacktrace, &ecx.machine);
437 any_pruned |= was_pruned;
438 report_msg(
439 DiagLevel::Error,
440 format!("deadlock: the evaluated program deadlocked"),
441 vec![format!("the evaluated program deadlocked")],
442 vec![],
443 vec![],
444 &stacktrace,
445 Some(thread),
446 &ecx.machine,
447 )
448 }
449 }
450 }
451
452 if any_pruned {
454 ecx.tcx.dcx().note(
455 "some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace",
456 );
457 }
458
459 for (i, frame) in ecx.active_thread_stack().iter().enumerate() {
461 trace!("-------------------");
462 trace!("Frame {}", i);
463 trace!(" return: {:?}", frame.return_place);
464 for (i, local) in frame.locals.iter().enumerate() {
465 trace!(" local {}: {:?}", i, local);
466 }
467 }
468
469 None
470}
471
472pub fn report_leaks<'tcx>(
473 ecx: &InterpCx<'tcx, MiriMachine<'tcx>>,
474 leaks: Vec<(AllocId, MemoryKind, Allocation<Provenance, AllocExtra<'tcx>, MiriAllocBytes>)>,
475) {
476 let mut any_pruned = false;
477 for (id, kind, alloc) in leaks {
478 let mut title = format!(
479 "memory leaked: {id:?} ({}, size: {:?}, align: {:?})",
480 kind,
481 alloc.size().bytes(),
482 alloc.align.bytes()
483 );
484 let Some(backtrace) = alloc.extra.backtrace else {
485 ecx.tcx.dcx().err(title);
486 continue;
487 };
488 title.push_str(", allocated here:");
489 let (backtrace, pruned) = prune_stacktrace(backtrace, &ecx.machine);
490 any_pruned |= pruned;
491 report_msg(
492 DiagLevel::Error,
493 title,
494 vec![],
495 vec![],
496 vec![],
497 &backtrace,
498 None, &ecx.machine,
500 );
501 }
502 if any_pruned {
503 ecx.tcx.dcx().note(
504 "some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace",
505 );
506 }
507}
508
509pub fn report_msg<'tcx>(
515 diag_level: DiagLevel,
516 title: String,
517 span_msg: Vec<String>,
518 notes: Vec<(Option<SpanData>, String)>,
519 helps: Vec<(Option<SpanData>, String)>,
520 stacktrace: &[FrameInfo<'tcx>],
521 thread: Option<ThreadId>,
522 machine: &MiriMachine<'tcx>,
523) {
524 let span = stacktrace.first().map_or(DUMMY_SP, |fi| fi.span);
525 let sess = machine.tcx.sess;
526 let level = match diag_level {
527 DiagLevel::Error => Level::Error,
528 DiagLevel::Warning => Level::Warning,
529 DiagLevel::Note => Level::Note,
530 };
531 let mut err = Diag::<()>::new(sess.dcx(), level, title);
532 err.span(span);
533
534 if span != DUMMY_SP {
536 for line in span_msg {
537 err.span_label(span, line);
538 }
539 } else {
540 for line in span_msg {
542 err.note(line);
543 }
544 err.note("(no span available)");
545 }
546
547 let mut extra_span = false;
549 for (span_data, note) in notes {
550 if let Some(span_data) = span_data {
551 err.span_note(span_data.span(), note);
552 extra_span = true;
553 } else {
554 err.note(note);
555 }
556 }
557 for (span_data, help) in helps {
558 if let Some(span_data) = span_data {
559 err.span_help(span_data.span(), help);
560 extra_span = true;
561 } else {
562 err.help(help);
563 }
564 }
565
566 let mut backtrace_title = String::from("BACKTRACE");
568 if extra_span {
569 write!(backtrace_title, " (of the first span)").unwrap();
570 }
571 if let Some(thread) = thread {
572 let thread_name = machine.threads.get_thread_display_name(thread);
573 if thread_name != "main" {
574 write!(backtrace_title, " on thread `{thread_name}`").unwrap();
576 };
577 }
578 write!(backtrace_title, ":").unwrap();
579 err.note(backtrace_title);
580 for (idx, frame_info) in stacktrace.iter().enumerate() {
581 let is_local = machine.is_local(frame_info);
582 if is_local && idx > 0 {
584 err.subdiagnostic(frame_info.as_note(machine.tcx));
585 } else {
586 let sm = sess.source_map();
587 let span = sm.span_to_embeddable_string(frame_info.span);
588 err.note(format!("{frame_info} at {span}"));
589 }
590 }
591
592 err.emit();
593}
594
595impl<'tcx> MiriMachine<'tcx> {
596 pub fn emit_diagnostic(&self, e: NonHaltingDiagnostic) {
597 use NonHaltingDiagnostic::*;
598
599 let stacktrace = Frame::generate_stacktrace_from_stack(self.threads.active_thread_stack());
600 let (stacktrace, _was_pruned) = prune_stacktrace(stacktrace, self);
601
602 let (title, diag_level) = match &e {
603 RejectedIsolatedOp(_) =>
604 ("operation rejected by isolation".to_string(), DiagLevel::Warning),
605 Int2Ptr { .. } => ("integer-to-pointer cast".to_string(), DiagLevel::Warning),
606 NativeCallSharedMem =>
607 ("sharing memory with a native function".to_string(), DiagLevel::Warning),
608 ExternTypeReborrow =>
609 ("reborrow of reference to `extern type`".to_string(), DiagLevel::Warning),
610 CreatedPointerTag(..)
611 | PoppedPointerTag(..)
612 | CreatedAlloc(..)
613 | AccessedAlloc(..)
614 | FreedAlloc(..)
615 | ProgressReport { .. }
616 | WeakMemoryOutdatedLoad { .. } =>
617 ("tracking was triggered".to_string(), DiagLevel::Note),
618 };
619
620 let msg = match &e {
621 CreatedPointerTag(tag, None, _) => format!("created base tag {tag:?}"),
622 CreatedPointerTag(tag, Some(perm), None) =>
623 format!("created {tag:?} with {perm} derived from unknown tag"),
624 CreatedPointerTag(tag, Some(perm), Some((alloc_id, range, orig_tag))) =>
625 format!(
626 "created tag {tag:?} with {perm} at {alloc_id:?}{range:?} derived from {orig_tag:?}"
627 ),
628 PoppedPointerTag(item, cause) => format!("popped tracked tag for item {item:?}{cause}"),
629 CreatedAlloc(AllocId(id), size, align, kind) =>
630 format!(
631 "created {kind} allocation of {size} bytes (alignment {align} bytes) with id {id}",
632 size = size.bytes(),
633 align = align.bytes(),
634 ),
635 AccessedAlloc(AllocId(id), access_kind) =>
636 format!("{access_kind} to allocation with id {id}"),
637 FreedAlloc(AllocId(id)) => format!("freed allocation with id {id}"),
638 RejectedIsolatedOp(ref op) =>
639 format!("{op} was made to return an error due to isolation"),
640 ProgressReport { .. } =>
641 format!("progress report: current operation being executed is here"),
642 Int2Ptr { .. } => format!("integer-to-pointer cast"),
643 NativeCallSharedMem => format!("sharing memory with a native function called via FFI"),
644 WeakMemoryOutdatedLoad { ptr } =>
645 format!("weak memory emulation: outdated value returned from load at {ptr}"),
646 ExternTypeReborrow =>
647 format!("reborrow of a reference to `extern type` is not properly supported"),
648 };
649
650 let notes = match &e {
651 ProgressReport { block_count } => {
652 vec![note!("so far, {block_count} basic blocks have been executed")]
653 }
654 _ => vec![],
655 };
656
657 let helps = match &e {
658 Int2Ptr { details: true } => {
659 let mut v = vec![
660 note!(
661 "this program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`, which means that Miri might miss pointer bugs in this program"
662 ),
663 note!(
664 "see https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html for more details on that operation"
665 ),
666 note!(
667 "to ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead"
668 ),
669 note!(
670 "you can then set `MIRIFLAGS=-Zmiri-strict-provenance` to ensure you are not relying on `with_exposed_provenance` semantics"
671 ),
672 ];
673 if self.borrow_tracker.as_ref().is_some_and(|b| {
674 matches!(b.borrow().borrow_tracker_method(), BorrowTrackerMethod::TreeBorrows)
675 }) {
676 v.push(
677 note!("Tree Borrows does not support integer-to-pointer casts, so the program is likely to go wrong when this pointer gets used")
678 );
679 } else {
680 v.push(
681 note!("alternatively, `MIRIFLAGS=-Zmiri-permissive-provenance` disables this warning")
682 );
683 }
684 v
685 }
686 NativeCallSharedMem => {
687 vec![
688 note!(
689 "when memory is shared with a native function call, Miri stops tracking initialization and provenance for that memory"
690 ),
691 note!(
692 "in particular, Miri assumes that the native call initializes all memory it has access to"
693 ),
694 note!(
695 "Miri also assumes that any part of this memory may be a pointer that is permitted to point to arbitrary exposed memory"
696 ),
697 note!(
698 "what this means is that Miri will easily miss Undefined Behavior related to incorrect usage of this shared memory, so you should not take a clean Miri run as a signal that your FFI code is UB-free"
699 ),
700 ]
701 }
702 ExternTypeReborrow => {
703 assert!(self.borrow_tracker.as_ref().is_some_and(|b| {
704 matches!(
705 b.borrow().borrow_tracker_method(),
706 BorrowTrackerMethod::StackedBorrows
707 )
708 }));
709 vec![
710 note!(
711 "`extern type` are not compatible with the Stacked Borrows aliasing model implemented by Miri; Miri may miss bugs in this code"
712 ),
713 note!(
714 "try running with `MIRIFLAGS=-Zmiri-tree-borrows` to use the more permissive but also even more experimental Tree Borrows aliasing checks instead"
715 ),
716 ]
717 }
718 _ => vec![],
719 };
720
721 report_msg(
722 diag_level,
723 title,
724 vec![msg],
725 notes,
726 helps,
727 &stacktrace,
728 Some(self.threads.active_thread()),
729 self,
730 );
731 }
732}
733
734impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
735pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
736 fn emit_diagnostic(&self, e: NonHaltingDiagnostic) {
737 let this = self.eval_context_ref();
738 this.machine.emit_diagnostic(e);
739 }
740
741 fn handle_ice(&self) {
743 eprintln!();
744 eprintln!(
745 "Miri caused an ICE during evaluation. Here's the interpreter backtrace at the time of the panic:"
746 );
747 let this = self.eval_context_ref();
748 let stacktrace = this.generate_stacktrace();
749 report_msg(
750 DiagLevel::Note,
751 "the place in the program where the ICE was triggered".to_string(),
752 vec![],
753 vec![],
754 vec![],
755 &stacktrace,
756 Some(this.active_thread()),
757 &this.machine,
758 );
759 }
760}