miri/diagnostics: don't forget to print_backtrace when ICEing on unexpected errors

then also use the new helper in a few other places
This commit is contained in:
Ralf Jung 2023-08-27 14:41:35 +02:00
parent b60f7b51a2
commit beeb2b13cc
5 changed files with 57 additions and 44 deletions

View File

@ -25,8 +25,8 @@
Scalar, StackPopJump, Scalar, StackPopJump,
}; };
use crate::errors::{self, ErroneousConstUsed}; use crate::errors::{self, ErroneousConstUsed};
use crate::fluent_generated as fluent;
use crate::util; use crate::util;
use crate::{fluent_generated as fluent, ReportErrorExt};
pub struct InterpCx<'mir, 'tcx, M: Machine<'mir, 'tcx>> { pub struct InterpCx<'mir, 'tcx, M: Machine<'mir, 'tcx>> {
/// Stores the `Machine` instance. /// Stores the `Machine` instance.
@ -432,6 +432,27 @@ pub fn best_lint_scope(&self) -> hir::HirId {
.map_or(CRATE_HIR_ID, |def_id| self.tcx.hir().local_def_id_to_hir_id(def_id)) .map_or(CRATE_HIR_ID, |def_id| self.tcx.hir().local_def_id_to_hir_id(def_id))
} }
/// Turn the given error into a human-readable string. Expects the string to be printed, so if
/// `RUSTC_CTFE_BACKTRACE` is set this will show a backtrace of the rustc internals that
/// triggered the error.
///
/// This is NOT the preferred way to render an error; use `report` from `const_eval` instead.
/// However, this is useful when error messages appear in ICEs.
pub fn format_error(&self, e: InterpErrorInfo<'tcx>) -> String {
let (e, backtrace) = e.into_parts();
backtrace.print_backtrace();
// FIXME(fee1-dead), HACK: we want to use the error as title therefore we can just extract the
// label and arguments from the InterpError.
let handler = &self.tcx.sess.parse_sess.span_diagnostic;
#[allow(rustc::untranslatable_diagnostic)]
let mut diag = self.tcx.sess.struct_allow("");
let msg = e.diagnostic_message();
e.add_args(handler, &mut diag);
let s = handler.eagerly_translate_to_string(msg, diag.args());
diag.cancel();
s
}
#[inline(always)] #[inline(always)]
pub(crate) fn stack(&self) -> &[Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>] { pub(crate) fn stack(&self) -> &[Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>] {
M::stack(self) M::stack(self)

View File

@ -378,7 +378,8 @@ pub fn intern_const_alloc_recursive<
ecx.tcx.sess.delay_span_bug( ecx.tcx.sess.delay_span_bug(
ecx.tcx.span, ecx.tcx.span,
format!( format!(
"error during interning should later cause validation failure: {error:?}" "error during interning should later cause validation failure: {}",
ecx.format_error(error),
), ),
); );
} }

View File

@ -911,9 +911,10 @@ fn validate_operand_internal(
// Complain about any other kind of error -- those are bad because we'd like to // Complain about any other kind of error -- those are bad because we'd like to
// report them in a way that shows *where* in the value the issue lies. // report them in a way that shows *where* in the value the issue lies.
Err(err) => { Err(err) => {
let (err, backtrace) = err.into_parts(); bug!(
backtrace.print_backtrace(); "Unexpected Undefined Behavior error during validation: {}",
bug!("Unexpected Undefined Behavior error during validation: {err:?}"); self.format_error(err)
);
} }
} }
} }

View File

@ -273,7 +273,8 @@ fn use_ecx<F, T>(&mut self, location: Location, f: F) -> Option<T>
// dedicated error variants should be introduced instead. // dedicated error variants should be introduced instead.
assert!( assert!(
!error.kind().formatted_string(), !error.kind().formatted_string(),
"const-prop encountered formatting error: {error:?}", "const-prop encountered formatting error: {}",
self.ecx.format_error(error),
); );
None None
} }

View File

@ -1,9 +1,8 @@
use std::fmt; use std::fmt::{self, Write};
use std::num::NonZeroU64; use std::num::NonZeroU64;
use log::trace; use log::trace;
use rustc_const_eval::ReportErrorExt;
use rustc_errors::DiagnosticMessage; use rustc_errors::DiagnosticMessage;
use rustc_span::{source_map::DUMMY_SP, SpanData, Symbol}; use rustc_span::{source_map::DUMMY_SP, SpanData, Symbol};
use rustc_target::abi::{Align, Size}; use rustc_target::abi::{Align, Size};
@ -271,10 +270,13 @@ pub fn report_error<'tcx, 'mir>(
}; };
(title, helps) (title, helps)
} else { } else {
#[rustfmt::skip]
let title = match e.kind() { let title = match e.kind() {
UndefinedBehavior(UndefinedBehaviorInfo::ValidationError(e)) if matches!(e.kind, ValidationErrorKind::PointerAsInt { .. } | ValidationErrorKind::PartialPointer) => UndefinedBehavior(UndefinedBehaviorInfo::ValidationError(validation_err))
bug!("This validation error should be impossible in Miri: {:?}", e.kind), if matches!(validation_err.kind, ValidationErrorKind::PointerAsInt { .. } | ValidationErrorKind::PartialPointer) =>
{
ecx.handle_ice(); // print interpreter backtrace
bug!("This validation error should be impossible in Miri: {}", ecx.format_error(e));
}
UndefinedBehavior(_) => UndefinedBehavior(_) =>
"Undefined Behavior", "Undefined Behavior",
ResourceExhaustion(_) => ResourceExhaustion(_) =>
@ -290,8 +292,10 @@ pub fn report_error<'tcx, 'mir>(
InvalidProgramInfo::Layout(..) InvalidProgramInfo::Layout(..)
) => ) =>
"post-monomorphization error", "post-monomorphization error",
kind => _ => {
bug!("This error should be impossible in Miri: {kind:?}"), ecx.handle_ice(); // print interpreter backtrace
bug!("This error should be impossible in Miri: {}", ecx.format_error(e));
}
}; };
#[rustfmt::skip] #[rustfmt::skip]
let helps = match e.kind() { let helps = match e.kind() {
@ -333,30 +337,22 @@ pub fn report_error<'tcx, 'mir>(
let stacktrace = ecx.generate_stacktrace(); let stacktrace = ecx.generate_stacktrace();
let (stacktrace, was_pruned) = prune_stacktrace(stacktrace, &ecx.machine); let (stacktrace, was_pruned) = prune_stacktrace(stacktrace, &ecx.machine);
let (e, backtrace) = e.into_parts();
backtrace.print_backtrace();
// We want to dump the allocation if this is `InvalidUninitBytes`. Since `add_args` consumes // We want to dump the allocation if this is `InvalidUninitBytes`. Since `format_error` consumes `e`, we compute the outut early.
// the `InterpError`, we extract the variables it before that. let mut extra = String::new();
let extra = match e { match e.kind() {
UndefinedBehavior(UndefinedBehaviorInfo::InvalidUninitBytes(Some((alloc_id, access)))) => UndefinedBehavior(UndefinedBehaviorInfo::InvalidUninitBytes(Some((alloc_id, access)))) => {
Some((alloc_id, access)), writeln!(
_ => None, extra,
}; "Uninitialized memory occurred at {alloc_id:?}{range:?}, in this allocation:",
range = access.bad,
).unwrap();
writeln!(extra, "{:?}", ecx.dump_alloc(*alloc_id)).unwrap();
}
_ => {}
}
// FIXME(fee1-dead), HACK: we want to use the error as title therefore we can just extract the msg.insert(0, ecx.format_error(e));
// label and arguments from the InterpError.
let e = {
let handler = &ecx.tcx.sess.parse_sess.span_diagnostic;
let mut diag = ecx.tcx.sess.struct_allow("");
let msg = e.diagnostic_message();
e.add_args(handler, &mut diag);
let s = handler.eagerly_translate_to_string(msg, diag.args());
diag.cancel();
s
};
msg.insert(0, e);
report_msg( report_msg(
DiagLevel::Error, DiagLevel::Error,
@ -375,6 +371,8 @@ pub fn report_error<'tcx, 'mir>(
); );
} }
eprint!("{extra}"); // newlines are already in the string
// Debug-dump all locals. // Debug-dump all locals.
for (i, frame) in ecx.active_thread_stack().iter().enumerate() { for (i, frame) in ecx.active_thread_stack().iter().enumerate() {
trace!("-------------------"); trace!("-------------------");
@ -385,15 +383,6 @@ pub fn report_error<'tcx, 'mir>(
} }
} }
// Extra output to help debug specific issues.
if let Some((alloc_id, access)) = extra {
eprintln!(
"Uninitialized memory occurred at {alloc_id:?}{range:?}, in this allocation:",
range = access.bad,
);
eprintln!("{:?}", ecx.dump_alloc(alloc_id));
}
None None
} }