• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use std::fmt;
2 use std::num::NonZeroU64;
3 
4 use log::trace;
5 
6 use rustc_const_eval::ReportErrorExt;
7 use rustc_errors::DiagnosticMessage;
8 use rustc_span::{source_map::DUMMY_SP, SpanData, Symbol};
9 use rustc_target::abi::{Align, Size};
10 
11 use crate::borrow_tracker::stacked_borrows::diagnostics::TagHistory;
12 use crate::borrow_tracker::tree_borrows::diagnostics as tree_diagnostics;
13 use crate::*;
14 
15 /// Details of premature program termination.
16 pub enum TerminationInfo {
17     Exit {
18         code: i64,
19         leak_check: bool,
20     },
21     Abort(String),
22     UnsupportedInIsolation(String),
23     StackedBorrowsUb {
24         msg: String,
25         help: Option<String>,
26         history: Option<TagHistory>,
27     },
28     TreeBorrowsUb {
29         title: String,
30         details: Vec<String>,
31         history: tree_diagnostics::HistoryData,
32     },
33     Int2PtrWithStrictProvenance,
34     Deadlock,
35     MultipleSymbolDefinitions {
36         link_name: Symbol,
37         first: SpanData,
38         first_crate: Symbol,
39         second: SpanData,
40         second_crate: Symbol,
41     },
42     SymbolShimClashing {
43         link_name: Symbol,
44         span: SpanData,
45     },
46     DataRace {
47         op1: RacingOp,
48         op2: RacingOp,
49         ptr: Pointer,
50     },
51 }
52 
53 pub struct RacingOp {
54     pub action: String,
55     pub thread_info: String,
56     pub span: SpanData,
57 }
58 
59 impl fmt::Display for TerminationInfo {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result60     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61         use TerminationInfo::*;
62         match self {
63             Exit { code, .. } => write!(f, "the evaluated program completed with exit code {code}"),
64             Abort(msg) => write!(f, "{msg}"),
65             UnsupportedInIsolation(msg) => write!(f, "{msg}"),
66             Int2PtrWithStrictProvenance =>
67                 write!(
68                     f,
69                     "integer-to-pointer casts and `ptr::from_exposed_addr` are not supported with `-Zmiri-strict-provenance`"
70                 ),
71             StackedBorrowsUb { msg, .. } => write!(f, "{msg}"),
72             TreeBorrowsUb { title, .. } => write!(f, "{title}"),
73             Deadlock => write!(f, "the evaluated program deadlocked"),
74             MultipleSymbolDefinitions { link_name, .. } =>
75                 write!(f, "multiple definitions of symbol `{link_name}`"),
76             SymbolShimClashing { link_name, .. } =>
77                 write!(f, "found `{link_name}` symbol definition that clashes with a built-in shim",),
78             DataRace { ptr, op1, op2 } =>
79                 write!(
80                     f,
81                     "Data race detected between (1) {} on {} and (2) {} on {} at {ptr:?}. (2) just happened here",
82                     op1.action, op1.thread_info, op2.action, op2.thread_info
83                 ),
84         }
85     }
86 }
87 
88 impl fmt::Debug for TerminationInfo {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result89     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
90         write!(f, "{self}")
91     }
92 }
93 
94 impl MachineStopType for TerminationInfo {
diagnostic_message(&self) -> DiagnosticMessage95     fn diagnostic_message(&self) -> DiagnosticMessage {
96         self.to_string().into()
97     }
add_args( self: Box<Self>, _: &mut dyn FnMut( std::borrow::Cow<'static, str>, rustc_errors::DiagnosticArgValue<'static>, ), )98     fn add_args(
99         self: Box<Self>,
100         _: &mut dyn FnMut(
101             std::borrow::Cow<'static, str>,
102             rustc_errors::DiagnosticArgValue<'static>,
103         ),
104     ) {
105     }
106 }
107 
108 /// Miri specific diagnostics
109 pub enum NonHaltingDiagnostic {
110     /// (new_tag, new_perm, (alloc_id, base_offset, orig_tag))
111     ///
112     /// new_perm is `None` for base tags.
113     CreatedPointerTag(NonZeroU64, Option<String>, Option<(AllocId, AllocRange, ProvenanceExtra)>),
114     /// This `Item` was popped from the borrow stack. The string explains the reason.
115     PoppedPointerTag(Item, String),
116     CreatedCallId(CallId),
117     CreatedAlloc(AllocId, Size, Align, MemoryKind<MiriMemoryKind>),
118     FreedAlloc(AllocId),
119     RejectedIsolatedOp(String),
120     ProgressReport {
121         block_count: u64, // how many basic blocks have been run so far
122     },
123     Int2Ptr {
124         details: bool,
125     },
126     WeakMemoryOutdatedLoad,
127 }
128 
129 /// Level of Miri specific diagnostics
130 pub enum DiagLevel {
131     Error,
132     Warning,
133     Note,
134 }
135 
136 /// Attempts to prune a stacktrace to omit the Rust runtime, and returns a bool indicating if any
137 /// frames were pruned. If the stacktrace does not have any local frames, we conclude that it must
138 /// be pointing to a problem in the Rust runtime itself, and do not prune it at all.
prune_stacktrace<'tcx>( mut stacktrace: Vec<FrameInfo<'tcx>>, machine: &MiriMachine<'_, 'tcx>, ) -> (Vec<FrameInfo<'tcx>>, bool)139 pub fn prune_stacktrace<'tcx>(
140     mut stacktrace: Vec<FrameInfo<'tcx>>,
141     machine: &MiriMachine<'_, 'tcx>,
142 ) -> (Vec<FrameInfo<'tcx>>, bool) {
143     match machine.backtrace_style {
144         BacktraceStyle::Off => {
145             // Remove all frames marked with `caller_location` -- that attribute indicates we
146             // usually want to point at the caller, not them.
147             stacktrace.retain(|frame| !frame.instance.def.requires_caller_location(machine.tcx));
148             // Retain one frame so that we can print a span for the error itself
149             stacktrace.truncate(1);
150             (stacktrace, false)
151         }
152         BacktraceStyle::Short => {
153             let original_len = stacktrace.len();
154             // Only prune frames if there is at least one local frame. This check ensures that if
155             // we get a backtrace that never makes it to the user code because it has detected a
156             // bug in the Rust runtime, we don't prune away every frame.
157             let has_local_frame = stacktrace.iter().any(|frame| machine.is_local(frame));
158             if has_local_frame {
159                 // Remove all frames marked with `caller_location` -- that attribute indicates we
160                 // usually want to point at the caller, not them.
161                 stacktrace
162                     .retain(|frame| !frame.instance.def.requires_caller_location(machine.tcx));
163 
164                 // This is part of the logic that `std` uses to select the relevant part of a
165                 // backtrace. But here, we only look for __rust_begin_short_backtrace, not
166                 // __rust_end_short_backtrace because the end symbol comes from a call to the default
167                 // panic handler.
168                 stacktrace = stacktrace
169                     .into_iter()
170                     .take_while(|frame| {
171                         let def_id = frame.instance.def_id();
172                         let path = machine.tcx.def_path_str(def_id);
173                         !path.contains("__rust_begin_short_backtrace")
174                     })
175                     .collect::<Vec<_>>();
176 
177                 // After we prune frames from the bottom, there are a few left that are part of the
178                 // Rust runtime. So we remove frames until we get to a local symbol, which should be
179                 // main or a test.
180                 // This len check ensures that we don't somehow remove every frame, as doing so breaks
181                 // the primary error message.
182                 while stacktrace.len() > 1
183                     && stacktrace.last().map_or(false, |frame| !machine.is_local(frame))
184                 {
185                     stacktrace.pop();
186                 }
187             }
188             let was_pruned = stacktrace.len() != original_len;
189             (stacktrace, was_pruned)
190         }
191         BacktraceStyle::Full => (stacktrace, false),
192     }
193 }
194 
195 /// Emit a custom diagnostic without going through the miri-engine machinery.
196 ///
197 /// Returns `Some` if this was regular program termination with a given exit code and a `bool` indicating whether a leak check should happen; `None` otherwise.
report_error<'tcx, 'mir>( ecx: &InterpCx<'mir, 'tcx, MiriMachine<'mir, 'tcx>>, e: InterpErrorInfo<'tcx>, ) -> Option<(i64, bool)>198 pub fn report_error<'tcx, 'mir>(
199     ecx: &InterpCx<'mir, 'tcx, MiriMachine<'mir, 'tcx>>,
200     e: InterpErrorInfo<'tcx>,
201 ) -> Option<(i64, bool)> {
202     use InterpError::*;
203 
204     let mut msg = vec![];
205 
206     let (title, helps) = if let MachineStop(info) = e.kind() {
207         let info = info.downcast_ref::<TerminationInfo>().expect("invalid MachineStop payload");
208         use TerminationInfo::*;
209         let title = match info {
210             Exit { code, leak_check } => return Some((*code, *leak_check)),
211             Abort(_) => Some("abnormal termination"),
212             UnsupportedInIsolation(_) | Int2PtrWithStrictProvenance =>
213                 Some("unsupported operation"),
214             StackedBorrowsUb { .. } | TreeBorrowsUb { .. } | DataRace { .. } =>
215                 Some("Undefined Behavior"),
216             Deadlock => Some("deadlock"),
217             MultipleSymbolDefinitions { .. } | SymbolShimClashing { .. } => None,
218         };
219         #[rustfmt::skip]
220         let helps = match info {
221             UnsupportedInIsolation(_) =>
222                 vec![
223                     (None, format!("pass the flag `-Zmiri-disable-isolation` to disable isolation;")),
224                     (None, format!("or pass `-Zmiri-isolation-error=warn` to configure Miri to return an error code from isolated operations (if supported for that operation) and continue with a warning")),
225                 ],
226             StackedBorrowsUb { help, history, .. } => {
227                 let url = "https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md";
228                 msg.extend(help.clone());
229                 let mut helps = vec![
230                     (None, format!("this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental")),
231                     (None, format!("see {url} for further information")),
232                 ];
233                 if let Some(TagHistory {created, invalidated, protected}) = history.clone() {
234                     helps.push((Some(created.1), created.0));
235                     if let Some((msg, span)) = invalidated {
236                         helps.push((Some(span), msg));
237                     }
238                     if let Some((protector_msg, protector_span)) = protected {
239                         helps.push((Some(protector_span), protector_msg));
240                     }
241                 }
242                 helps
243             },
244             TreeBorrowsUb { title: _, details, history } => {
245                 let mut helps = vec![
246                     (None, format!("this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental"))
247                 ];
248                 for m in details {
249                     helps.push((None, m.clone()));
250                 }
251                 for event in history.events.clone() {
252                     helps.push(event);
253                 }
254                 helps
255             }
256             MultipleSymbolDefinitions { first, first_crate, second, second_crate, .. } =>
257                 vec![
258                     (Some(*first), format!("it's first defined here, in crate `{first_crate}`")),
259                     (Some(*second), format!("then it's defined here again, in crate `{second_crate}`")),
260                 ],
261             SymbolShimClashing { link_name, span } =>
262                 vec![(Some(*span), format!("the `{link_name}` symbol is defined here"))],
263             Int2PtrWithStrictProvenance =>
264                 vec![(None, format!("use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead"))],
265             DataRace { op1, .. } =>
266                 vec![
267                     (Some(op1.span), format!("and (1) occurred earlier here")),
268                     (None, format!("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior")),
269                     (None, format!("see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information")),
270                 ],
271             _ => vec![],
272         };
273         (title, helps)
274     } else {
275         #[rustfmt::skip]
276         let title = match e.kind() {
277             UndefinedBehavior(_) =>
278                 "Undefined Behavior",
279             ResourceExhaustion(_) =>
280                 "resource exhaustion",
281             Unsupported(
282                 // We list only the ones that can actually happen.
283                 UnsupportedOpInfo::Unsupported(_)
284             ) =>
285                 "unsupported operation",
286             InvalidProgram(
287                 // We list only the ones that can actually happen.
288                 InvalidProgramInfo::AlreadyReported(_) |
289                 InvalidProgramInfo::Layout(..)
290             ) =>
291                 "post-monomorphization error",
292             kind =>
293                 bug!("This error should be impossible in Miri: {kind:?}"),
294         };
295         #[rustfmt::skip]
296         let helps = match e.kind() {
297             Unsupported(_) =>
298                 vec![(None, format!("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support"))],
299             UndefinedBehavior(UndefinedBehaviorInfo::AlignmentCheckFailed { .. })
300                 if ecx.machine.check_alignment == AlignmentCheck::Symbolic
301             =>
302                 vec![
303                     (None, format!("this usually indicates that your program performed an invalid operation and caused Undefined Behavior")),
304                     (None, format!("but due to `-Zmiri-symbolic-alignment-check`, alignment errors can also be false positives")),
305                 ],
306             UndefinedBehavior(_) =>
307                 vec![
308                     (None, format!("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior")),
309                     (None, format!("see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information")),
310                 ],
311             InvalidProgram(
312                 InvalidProgramInfo::AlreadyReported(_)
313             ) => {
314                 // This got already reported. No point in reporting it again.
315                 return None;
316             }
317             _ =>
318                 vec![],
319         };
320         (Some(title), helps)
321     };
322 
323     let stacktrace = ecx.generate_stacktrace();
324     let (stacktrace, was_pruned) = prune_stacktrace(stacktrace, &ecx.machine);
325     let (e, backtrace) = e.into_parts();
326     backtrace.print_backtrace();
327 
328     // We want to dump the allocation if this is `InvalidUninitBytes`. Since `add_args` consumes
329     // the `InterpError`, we extract the variables it before that.
330     let extra = match e {
331         UndefinedBehavior(UndefinedBehaviorInfo::InvalidUninitBytes(Some((alloc_id, access)))) =>
332             Some((alloc_id, access)),
333         _ => None,
334     };
335 
336     // FIXME(fee1-dead), HACK: we want to use the error as title therefore we can just extract the
337     // label and arguments from the InterpError.
338     let e = {
339         let handler = &ecx.tcx.sess.parse_sess.span_diagnostic;
340         let mut diag = ecx.tcx.sess.struct_allow("");
341         let msg = e.diagnostic_message();
342         e.add_args(handler, &mut diag);
343         let s = handler.eagerly_translate_to_string(msg, diag.args());
344         diag.cancel();
345         s
346     };
347 
348     msg.insert(0, e);
349 
350     report_msg(
351         DiagLevel::Error,
352         if let Some(title) = title { format!("{title}: {}", msg[0]) } else { msg[0].clone() },
353         msg,
354         vec![],
355         helps,
356         &stacktrace,
357         &ecx.machine,
358     );
359 
360     // Include a note like `std` does when we omit frames from a backtrace
361     if was_pruned {
362         ecx.tcx.sess.diagnostic().note_without_error(
363             "some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace",
364         );
365     }
366 
367     // Debug-dump all locals.
368     for (i, frame) in ecx.active_thread_stack().iter().enumerate() {
369         trace!("-------------------");
370         trace!("Frame {}", i);
371         trace!("    return: {:?}", *frame.return_place);
372         for (i, local) in frame.locals.iter().enumerate() {
373             trace!("    local {}: {:?}", i, local.value);
374         }
375     }
376 
377     // Extra output to help debug specific issues.
378     if let Some((alloc_id, access)) = extra {
379         eprintln!(
380             "Uninitialized memory occurred at {alloc_id:?}{range:?}, in this allocation:",
381             range = access.uninit,
382         );
383         eprintln!("{:?}", ecx.dump_alloc(alloc_id));
384     }
385 
386     None
387 }
388 
report_leaks<'mir, 'tcx>( ecx: &InterpCx<'mir, 'tcx, MiriMachine<'mir, 'tcx>>, leaks: Vec<(AllocId, MemoryKind<MiriMemoryKind>, Allocation<Provenance, AllocExtra<'tcx>>)>, )389 pub fn report_leaks<'mir, 'tcx>(
390     ecx: &InterpCx<'mir, 'tcx, MiriMachine<'mir, 'tcx>>,
391     leaks: Vec<(AllocId, MemoryKind<MiriMemoryKind>, Allocation<Provenance, AllocExtra<'tcx>>)>,
392 ) {
393     let mut any_pruned = false;
394     for (id, kind, mut alloc) in leaks {
395         let Some(backtrace) = alloc.extra.backtrace.take() else {
396             continue;
397         };
398         let (backtrace, pruned) = prune_stacktrace(backtrace, &ecx.machine);
399         any_pruned |= pruned;
400         report_msg(
401             DiagLevel::Error,
402             format!(
403                 "memory leaked: {id:?} ({}, size: {:?}, align: {:?}), allocated here:",
404                 kind,
405                 alloc.size().bytes(),
406                 alloc.align.bytes()
407             ),
408             vec![],
409             vec![],
410             vec![],
411             &backtrace,
412             &ecx.machine,
413         );
414     }
415     if any_pruned {
416         ecx.tcx.sess.diagnostic().note_without_error(
417             "some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace",
418         );
419     }
420 }
421 
422 /// Report an error or note (depending on the `error` argument) with the given stacktrace.
423 /// Also emits a full stacktrace of the interpreter stack.
424 /// We want to present a multi-line span message for some errors. Diagnostics do not support this
425 /// directly, so we pass the lines as a `Vec<String>` and display each line after the first with an
426 /// additional `span_label` or `note` call.
report_msg<'tcx>( diag_level: DiagLevel, title: String, span_msg: Vec<String>, notes: Vec<(Option<SpanData>, String)>, helps: Vec<(Option<SpanData>, String)>, stacktrace: &[FrameInfo<'tcx>], machine: &MiriMachine<'_, 'tcx>, )427 pub fn report_msg<'tcx>(
428     diag_level: DiagLevel,
429     title: String,
430     span_msg: Vec<String>,
431     notes: Vec<(Option<SpanData>, String)>,
432     helps: Vec<(Option<SpanData>, String)>,
433     stacktrace: &[FrameInfo<'tcx>],
434     machine: &MiriMachine<'_, 'tcx>,
435 ) {
436     let span = stacktrace.first().map_or(DUMMY_SP, |fi| fi.span);
437     let sess = machine.tcx.sess;
438     let mut err = match diag_level {
439         DiagLevel::Error => sess.struct_span_err(span, title).forget_guarantee(),
440         DiagLevel::Warning => sess.struct_span_warn(span, title),
441         DiagLevel::Note => sess.diagnostic().span_note_diag(span, title),
442     };
443 
444     // Show main message.
445     if span != DUMMY_SP {
446         for line in span_msg {
447             err.span_label(span, line);
448         }
449     } else {
450         // Make sure we show the message even when it is a dummy span.
451         for line in span_msg {
452             err.note(line);
453         }
454         err.note("(no span available)");
455     }
456 
457     // Show note and help messages.
458     let mut extra_span = false;
459     let notes_len = notes.len();
460     for (span_data, note) in notes {
461         if let Some(span_data) = span_data {
462             err.span_note(span_data.span(), note);
463             extra_span = true;
464         } else {
465             err.note(note);
466         }
467     }
468     let helps_len = helps.len();
469     for (span_data, help) in helps {
470         if let Some(span_data) = span_data {
471             err.span_help(span_data.span(), help);
472             extra_span = true;
473         } else {
474             err.help(help);
475         }
476     }
477     if notes_len + helps_len > 0 {
478         // Add visual separator before backtrace.
479         err.note(if extra_span { "BACKTRACE (of the first span):" } else { "BACKTRACE:" });
480     }
481 
482     let (mut err, handler) = err.into_diagnostic().unwrap();
483 
484     // Add backtrace
485     for (idx, frame_info) in stacktrace.iter().enumerate() {
486         let is_local = machine.is_local(frame_info);
487         // No span for non-local frames and the first frame (which is the error site).
488         if is_local && idx > 0 {
489             err.eager_subdiagnostic(handler, frame_info.as_note(machine.tcx));
490         } else {
491             let sm = sess.source_map();
492             let span = sm.span_to_embeddable_string(frame_info.span);
493             err.note(format!("{frame_info} at {span}"));
494         }
495     }
496 
497     handler.emit_diagnostic(&mut err);
498 }
499 
500 impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {
emit_diagnostic(&self, e: NonHaltingDiagnostic)501     pub fn emit_diagnostic(&self, e: NonHaltingDiagnostic) {
502         use NonHaltingDiagnostic::*;
503 
504         let stacktrace =
505             MiriInterpCx::generate_stacktrace_from_stack(self.threads.active_thread_stack());
506         let (stacktrace, _was_pruned) = prune_stacktrace(stacktrace, self);
507 
508         let (title, diag_level) = match &e {
509             RejectedIsolatedOp(_) =>
510                 ("operation rejected by isolation".to_string(), DiagLevel::Warning),
511             Int2Ptr { .. } => ("integer-to-pointer cast".to_string(), DiagLevel::Warning),
512             CreatedPointerTag(..)
513             | PoppedPointerTag(..)
514             | CreatedCallId(..)
515             | CreatedAlloc(..)
516             | FreedAlloc(..)
517             | ProgressReport { .. }
518             | WeakMemoryOutdatedLoad => ("tracking was triggered".to_string(), DiagLevel::Note),
519         };
520 
521         let msg = match &e {
522             CreatedPointerTag(tag, None, _) => format!("created base tag {tag:?}"),
523             CreatedPointerTag(tag, Some(perm), None) =>
524                 format!("created {tag:?} with {perm} derived from unknown tag"),
525             CreatedPointerTag(tag, Some(perm), Some((alloc_id, range, orig_tag))) =>
526                 format!(
527                     "created tag {tag:?} with {perm} at {alloc_id:?}{range:?} derived from {orig_tag:?}"
528                 ),
529             PoppedPointerTag(item, cause) => format!("popped tracked tag for item {item:?}{cause}"),
530             CreatedCallId(id) => format!("function call with id {id}"),
531             CreatedAlloc(AllocId(id), size, align, kind) =>
532                 format!(
533                     "created {kind} allocation of {size} bytes (alignment {align} bytes) with id {id}",
534                     size = size.bytes(),
535                     align = align.bytes(),
536                 ),
537             FreedAlloc(AllocId(id)) => format!("freed allocation with id {id}"),
538             RejectedIsolatedOp(ref op) =>
539                 format!("{op} was made to return an error due to isolation"),
540             ProgressReport { .. } =>
541                 format!("progress report: current operation being executed is here"),
542             Int2Ptr { .. } => format!("integer-to-pointer cast"),
543             WeakMemoryOutdatedLoad =>
544                 format!("weak memory emulation: outdated value returned from load"),
545         };
546 
547         let notes = match &e {
548             ProgressReport { block_count } => {
549                 // It is important that each progress report is slightly different, since
550                 // identical diagnostics are being deduplicated.
551                 vec![(None, format!("so far, {block_count} basic blocks have been executed"))]
552             }
553             _ => vec![],
554         };
555 
556         let helps = match &e {
557             Int2Ptr { details: true } =>
558                 vec![
559                     (
560                         None,
561                         format!(
562                             "This program is using integer-to-pointer casts or (equivalently) `ptr::from_exposed_addr`,"
563                         ),
564                     ),
565                     (
566                         None,
567                         format!("which means that Miri might miss pointer bugs in this program."),
568                     ),
569                     (
570                         None,
571                         format!(
572                             "See https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation."
573                         ),
574                     ),
575                     (
576                         None,
577                         format!(
578                             "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."
579                         ),
580                     ),
581                     (
582                         None,
583                         format!(
584                             "You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics."
585                         ),
586                     ),
587                     (
588                         None,
589                         format!(
590                             "Alternatively, the `-Zmiri-permissive-provenance` flag disables this warning."
591                         ),
592                     ),
593                 ],
594             _ => vec![],
595         };
596 
597         report_msg(diag_level, title, vec![msg], notes, helps, &stacktrace, self);
598     }
599 }
600 
601 impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
602 pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
emit_diagnostic(&self, e: NonHaltingDiagnostic)603     fn emit_diagnostic(&self, e: NonHaltingDiagnostic) {
604         let this = self.eval_context_ref();
605         this.machine.emit_diagnostic(e);
606     }
607 
608     /// We had a panic in Miri itself, try to print something useful.
handle_ice(&self)609     fn handle_ice(&self) {
610         eprintln!();
611         eprintln!(
612             "Miri caused an ICE during evaluation. Here's the interpreter backtrace at the time of the panic:"
613         );
614         let this = self.eval_context_ref();
615         let stacktrace = this.generate_stacktrace();
616         report_msg(
617             DiagLevel::Note,
618             "the place in the program where the ICE was triggered".to_string(),
619             vec![],
620             vec![],
621             vec![],
622             &stacktrace,
623             &this.machine,
624         );
625     }
626 }
627