From f1c649890b517997b0bab3b303415e2f6ceea476 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sat, 26 Feb 2022 17:02:17 -0500 Subject: [PATCH] Only print the pruning note if the trace was definitely pruned --- src/diagnostics.rs | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 8494f8a8ef0f..2b210a6de691 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -75,24 +75,26 @@ enum DiagLevel { Note, } -fn has_local_frame(stacktrace: &[FrameInfo<'_>]) -> bool { - stacktrace.iter().any(|frame| frame.instance.def_id().is_local()) -} - +/// Attempts to prune a stacktrace to omit the Rust runtime, and returns a bool indicating if any +/// frames were pruned. If the stacktrace does not have any local frames, we conclude that it must +/// be pointing to a problem in the Rust runtime itself, and do not prune it at all. fn prune_stacktrace<'mir, 'tcx>( ecx: &InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, mut stacktrace: Vec>, -) -> Vec> { +) -> (Vec>, bool) { match ecx.machine.backtrace_style { BacktraceStyle::Off => { // Retain one frame so that we can print a span for the error itself stacktrace.truncate(1); + (stacktrace, false) } BacktraceStyle::Short => { + let original_len = stacktrace.len(); // Only prune frames if there is at least one local frame. This check ensures that if // we get a backtrace that never makes it to the user code because it has detected a // bug in the Rust runtime, we don't prune away every frame. - if has_local_frame(&stacktrace) { + let has_local_frame = stacktrace.iter().any(|frame| frame.instance.def_id().is_local()); + if has_local_frame { // This is part of the logic that `std` uses to select the relevant part of a // backtrace. But here, we only look for __rust_begin_short_backtrace, not // __rust_end_short_backtrace because the end symbol comes from a call to the default @@ -117,10 +119,11 @@ fn prune_stacktrace<'mir, 'tcx>( stacktrace.pop(); } } + let was_pruned = stacktrace.len() != original_len; + (stacktrace, was_pruned) } - BacktraceStyle::Full => {} + BacktraceStyle::Full => (stacktrace, false), } - stacktrace } /// Emit a custom diagnostic without going through the miri-engine machinery @@ -206,7 +209,7 @@ pub fn report_error<'tcx, 'mir>( }; let stacktrace = ecx.generate_stacktrace(); - let stacktrace = prune_stacktrace(ecx, stacktrace); + let (stacktrace, was_pruned) = prune_stacktrace(ecx, stacktrace); e.print_backtrace(); let msg = e.to_string(); report_msg( @@ -218,9 +221,8 @@ pub fn report_error<'tcx, 'mir>( &stacktrace, ); - // Include a note like `std` does for short backtraces, but since we are opt-out not opt-in, we - // do not include a note when backtraces are off. - if ecx.machine.backtrace_style == BacktraceStyle::Short && has_local_frame(&stacktrace) { + // Include a note like `std` does when we omit frames from a backtrace + if was_pruned { ecx.tcx.sess.diagnostic().note_without_error( "some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace", ); @@ -377,7 +379,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ); } - let stacktrace = prune_stacktrace(this, stacktrace); + let (stacktrace, _was_pruned) = prune_stacktrace(this, stacktrace); // Show diagnostics. for e in diagnostics.drain(..) {