2019-12-22 17:42:04 -05:00
|
|
|
use super::{CheckInAllocMsg, Pointer, RawConst, ScalarMaybeUndef};
|
2017-08-02 16:59:01 +02:00
|
|
|
|
2019-02-05 11:20:45 -06:00
|
|
|
use crate::hir::map::definitions::DefPathData;
|
|
|
|
use crate::mir;
|
2020-02-15 11:56:23 +13:00
|
|
|
use crate::mir::interpret::ConstValue;
|
2019-12-22 17:42:04 -05:00
|
|
|
use crate::ty::layout::{Align, LayoutError, Size};
|
2019-09-06 03:57:44 +01:00
|
|
|
use crate::ty::query::TyCtxtAt;
|
2019-12-22 17:42:04 -05:00
|
|
|
use crate::ty::{self, layout, Ty};
|
2017-07-21 13:39:06 +02:00
|
|
|
|
2017-08-03 12:37:52 +02:00
|
|
|
use backtrace::Backtrace;
|
2020-01-09 11:18:47 +01:00
|
|
|
use rustc_errors::{struct_span_err, DiagnosticBuilder};
|
2020-01-05 02:37:57 +01:00
|
|
|
use rustc_hir as hir;
|
2019-09-06 03:57:44 +01:00
|
|
|
use rustc_macros::HashStable;
|
2019-12-31 20:15:40 +03:00
|
|
|
use rustc_span::{Pos, Span};
|
2019-09-06 03:57:44 +01:00
|
|
|
use rustc_target::spec::abi::Abi;
|
2019-12-22 17:42:04 -05:00
|
|
|
use std::{any::Any, env, fmt};
|
2019-09-06 03:57:44 +01:00
|
|
|
|
2019-04-05 13:11:44 +02:00
|
|
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, RustcEncodable, RustcDecodable)]
|
2018-08-26 15:19:34 +02:00
|
|
|
pub enum ErrorHandled {
|
2019-02-08 14:53:55 +01:00
|
|
|
/// Already reported a lint or an error for this evaluation.
|
2018-08-26 15:19:34 +02:00
|
|
|
Reported,
|
|
|
|
/// Don't emit an error, the evaluation failed because the MIR was generic
|
|
|
|
/// and the substs didn't fully monomorphize it.
|
|
|
|
TooGeneric,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ErrorHandled {
|
|
|
|
pub fn assert_reported(self) {
|
|
|
|
match self {
|
2019-12-22 17:42:04 -05:00
|
|
|
ErrorHandled::Reported => {}
|
|
|
|
ErrorHandled::TooGeneric => bug!(
|
|
|
|
"MIR interpretation failed without reporting an error \
|
2020-01-03 13:31:56 +01:00
|
|
|
even though it was fully monomorphized"
|
2019-12-22 17:42:04 -05:00
|
|
|
),
|
2018-08-26 15:19:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-31 10:23:22 +02:00
|
|
|
CloneTypeFoldableImpls! {
|
|
|
|
ErrorHandled,
|
|
|
|
}
|
|
|
|
|
2018-11-06 14:17:40 +01:00
|
|
|
pub type ConstEvalRawResult<'tcx> = Result<RawConst<'tcx>, ErrorHandled>;
|
2020-02-15 11:56:23 +13:00
|
|
|
pub type ConstEvalResult<'tcx> = Result<ConstValue<'tcx>, ErrorHandled>;
|
2018-06-25 18:46:02 +02:00
|
|
|
|
2019-12-01 11:42:19 +01:00
|
|
|
#[derive(Debug)]
|
2018-06-25 18:46:02 +02:00
|
|
|
pub struct ConstEvalErr<'tcx> {
|
|
|
|
pub span: Span,
|
2019-07-24 10:24:55 +02:00
|
|
|
pub error: crate::mir::interpret::InterpError<'tcx>,
|
2018-11-14 17:25:06 +01:00
|
|
|
pub stacktrace: Vec<FrameInfo<'tcx>>,
|
2018-06-25 18:46:02 +02:00
|
|
|
}
|
|
|
|
|
2019-12-01 11:42:19 +01:00
|
|
|
#[derive(Debug)]
|
2018-11-14 17:25:06 +01:00
|
|
|
pub struct FrameInfo<'tcx> {
|
2019-02-28 22:43:53 +00:00
|
|
|
/// This span is in the caller.
|
|
|
|
pub call_site: Span,
|
2018-11-14 17:25:06 +01:00
|
|
|
pub instance: ty::Instance<'tcx>,
|
2019-02-22 15:48:14 +01:00
|
|
|
pub lint_root: Option<hir::HirId>,
|
2018-06-25 18:46:02 +02:00
|
|
|
}
|
|
|
|
|
2018-11-14 17:25:06 +01:00
|
|
|
impl<'tcx> fmt::Display for FrameInfo<'tcx> {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
ty::tls::with(|tcx| {
|
|
|
|
if tcx.def_key(self.instance.def_id()).disambiguated_data.data
|
|
|
|
== DefPathData::ClosureExpr
|
|
|
|
{
|
2018-11-14 23:14:57 +01:00
|
|
|
write!(f, "inside call to closure")?;
|
2018-11-14 17:25:06 +01:00
|
|
|
} else {
|
2018-11-14 23:14:57 +01:00
|
|
|
write!(f, "inside call to `{}`", self.instance)?;
|
2018-11-14 17:25:06 +01:00
|
|
|
}
|
2018-11-15 08:59:49 +01:00
|
|
|
if !self.call_site.is_dummy() {
|
2019-04-05 22:42:40 +03:00
|
|
|
let lo = tcx.sess.source_map().lookup_char_pos(self.call_site.lo());
|
|
|
|
write!(f, " at {}:{}:{}", lo.file.name, lo.line, lo.col.to_usize() + 1)?;
|
2018-11-14 23:14:57 +01:00
|
|
|
}
|
|
|
|
Ok(())
|
2018-11-14 17:25:06 +01:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-14 00:48:52 +03:00
|
|
|
impl<'tcx> ConstEvalErr<'tcx> {
|
2019-06-12 00:11:55 +03:00
|
|
|
pub fn struct_error(
|
|
|
|
&self,
|
2019-06-14 00:48:52 +03:00
|
|
|
tcx: TyCtxtAt<'tcx>,
|
2019-06-12 00:11:55 +03:00
|
|
|
message: &str,
|
2020-01-31 22:24:57 +10:00
|
|
|
emit: impl FnOnce(DiagnosticBuilder<'_>),
|
|
|
|
) -> Result<(), ErrorHandled> {
|
|
|
|
self.struct_generic(tcx, message, emit, None)
|
2018-06-25 18:46:02 +02:00
|
|
|
}
|
|
|
|
|
2019-06-14 00:48:52 +03:00
|
|
|
pub fn report_as_error(&self, tcx: TyCtxtAt<'tcx>, message: &str) -> ErrorHandled {
|
2020-01-31 22:24:57 +10:00
|
|
|
match self.struct_error(tcx, message, |mut e| e.emit()) {
|
|
|
|
Ok(_) => ErrorHandled::Reported,
|
|
|
|
Err(x) => x,
|
2018-06-25 18:46:02 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-12 00:11:55 +03:00
|
|
|
pub fn report_as_lint(
|
|
|
|
&self,
|
2019-06-14 00:48:52 +03:00
|
|
|
tcx: TyCtxtAt<'tcx>,
|
2018-06-25 18:46:02 +02:00
|
|
|
message: &str,
|
2019-02-22 15:48:14 +01:00
|
|
|
lint_root: hir::HirId,
|
2019-03-10 17:28:52 -07:00
|
|
|
span: Option<Span>,
|
2018-08-26 15:19:34 +02:00
|
|
|
) -> ErrorHandled {
|
2020-01-31 22:24:57 +10:00
|
|
|
match self.struct_generic(
|
|
|
|
tcx,
|
|
|
|
message,
|
|
|
|
|mut lint: DiagnosticBuilder<'_>| {
|
|
|
|
// Apply the span.
|
2019-03-10 17:28:52 -07:00
|
|
|
if let Some(span) = span {
|
|
|
|
let primary_spans = lint.span.primary_spans().to_vec();
|
|
|
|
// point at the actual error as the primary span
|
|
|
|
lint.replace_span_with(span);
|
|
|
|
// point to the `const` statement as a secondary span
|
|
|
|
// they don't have any label
|
|
|
|
for sp in primary_spans {
|
2019-03-11 09:43:05 -07:00
|
|
|
if sp != span {
|
|
|
|
lint.span_label(sp, "");
|
|
|
|
}
|
2019-03-10 17:28:52 -07:00
|
|
|
}
|
|
|
|
}
|
2018-08-26 15:19:34 +02:00
|
|
|
lint.emit();
|
2020-02-02 09:47:58 +10:00
|
|
|
},
|
|
|
|
Some(lint_root),
|
|
|
|
) {
|
|
|
|
Ok(_) => ErrorHandled::Reported,
|
2018-08-26 15:19:34 +02:00
|
|
|
Err(err) => err,
|
2018-06-25 18:46:02 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-11 11:27:33 +01:00
|
|
|
/// Create a diagnostic for this const eval error.
|
|
|
|
///
|
|
|
|
/// Sets the message passed in via `message` and adds span labels with detailed error
|
|
|
|
/// information before handing control back to `emit` to do any final processing.
|
|
|
|
/// It's the caller's responsibility to call emit(), stash(), etc. within the `emit`
|
|
|
|
/// function to dispose of the diagnostic properly.
|
|
|
|
///
|
|
|
|
/// If `lint_root.is_some()` report it as a lint, else report it as a hard error.
|
|
|
|
/// (Except that for some errors, we ignore all that -- see `must_error` below.)
|
2018-06-25 18:46:02 +02:00
|
|
|
fn struct_generic(
|
|
|
|
&self,
|
2019-06-14 00:48:52 +03:00
|
|
|
tcx: TyCtxtAt<'tcx>,
|
2018-06-25 18:46:02 +02:00
|
|
|
message: &str,
|
2020-01-31 22:24:57 +10:00
|
|
|
emit: impl FnOnce(DiagnosticBuilder<'_>),
|
2019-02-22 15:48:14 +01:00
|
|
|
lint_root: Option<hir::HirId>,
|
2020-01-31 22:24:57 +10:00
|
|
|
) -> Result<(), ErrorHandled> {
|
2019-08-03 13:37:44 -07:00
|
|
|
let must_error = match self.error {
|
2020-01-03 13:33:28 +01:00
|
|
|
err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => {
|
2019-12-22 17:42:04 -05:00
|
|
|
return Err(ErrorHandled::TooGeneric);
|
|
|
|
}
|
|
|
|
err_inval!(TypeckError) => return Err(ErrorHandled::Reported),
|
2020-02-11 11:27:33 +01:00
|
|
|
// We must *always* hard error on these, even if the caller wants just a lint.
|
2019-08-03 13:37:44 -07:00
|
|
|
err_inval!(Layout(LayoutError::SizeOverflow(_))) => true,
|
|
|
|
_ => false,
|
|
|
|
};
|
2018-06-25 18:46:02 +02:00
|
|
|
trace!("reporting const eval failure at {:?}", self.span);
|
2020-01-31 22:24:57 +10:00
|
|
|
|
2020-02-08 22:21:20 +01:00
|
|
|
let err_msg = match &self.error {
|
|
|
|
InterpError::MachineStop(msg) => {
|
|
|
|
// A custom error (`ConstEvalErrKind` in `librustc_mir/interp/const_eval/error.rs`).
|
|
|
|
// Should be turned into a string by now.
|
|
|
|
msg.downcast_ref::<String>().expect("invalid MachineStop payload").clone()
|
|
|
|
}
|
|
|
|
err => err.to_string(),
|
|
|
|
};
|
|
|
|
|
2020-02-11 11:27:33 +01:00
|
|
|
let finish = |mut err: DiagnosticBuilder<'_>, span_msg: Option<String>| {
|
|
|
|
if let Some(span_msg) = span_msg {
|
|
|
|
err.span_label(self.span, span_msg);
|
2020-01-31 22:24:57 +10:00
|
|
|
}
|
2020-02-11 11:27:33 +01:00
|
|
|
// Add spans for the stacktrace.
|
2020-01-31 22:24:57 +10:00
|
|
|
// Skip the last, which is just the environment of the constant. The stacktrace
|
|
|
|
// is sometimes empty because we create "fake" eval contexts in CTFE to do work
|
|
|
|
// on constant values.
|
2020-02-28 14:20:33 +01:00
|
|
|
if !self.stacktrace.is_empty() {
|
2020-01-31 22:24:57 +10:00
|
|
|
for frame_info in &self.stacktrace[..self.stacktrace.len() - 1] {
|
|
|
|
err.span_label(frame_info.call_site, frame_info.to_string());
|
|
|
|
}
|
|
|
|
}
|
2020-02-11 11:27:33 +01:00
|
|
|
// Let the caller finish the job.
|
|
|
|
emit(err)
|
2020-01-31 22:24:57 +10:00
|
|
|
};
|
|
|
|
|
2020-02-11 11:27:33 +01:00
|
|
|
if must_error {
|
|
|
|
// The `message` makes little sense here, this is a more serious error than the
|
|
|
|
// caller thinks anyway.
|
2020-02-10 15:58:10 +01:00
|
|
|
// See <https://github.com/rust-lang/rust/pull/63152>.
|
2020-02-11 11:27:33 +01:00
|
|
|
finish(struct_error(tcx, &err_msg), None);
|
2018-06-25 18:46:02 +02:00
|
|
|
} else {
|
2020-02-11 11:27:33 +01:00
|
|
|
// Regular case.
|
|
|
|
if let Some(lint_root) = lint_root {
|
|
|
|
// Report as lint.
|
|
|
|
let hir_id = self
|
|
|
|
.stacktrace
|
|
|
|
.iter()
|
|
|
|
.rev()
|
|
|
|
.filter_map(|frame| frame.lint_root)
|
|
|
|
.next()
|
|
|
|
.unwrap_or(lint_root);
|
|
|
|
tcx.struct_span_lint_hir(
|
|
|
|
rustc_session::lint::builtin::CONST_ERR,
|
|
|
|
hir_id,
|
|
|
|
tcx.span,
|
|
|
|
|lint| finish(lint.build(message), Some(err_msg)),
|
|
|
|
);
|
2020-01-31 22:24:57 +10:00
|
|
|
} else {
|
2020-02-11 11:27:33 +01:00
|
|
|
// Report as hard error.
|
|
|
|
finish(struct_error(tcx, message), Some(err_msg));
|
|
|
|
}
|
|
|
|
}
|
2020-01-31 22:24:57 +10:00
|
|
|
Ok(())
|
2018-06-25 18:46:02 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-14 00:48:52 +03:00
|
|
|
pub fn struct_error<'tcx>(tcx: TyCtxtAt<'tcx>, msg: &str) -> DiagnosticBuilder<'tcx> {
|
2018-06-25 18:46:02 +02:00
|
|
|
struct_span_err!(tcx.sess, tcx.span, E0080, "{}", msg)
|
|
|
|
}
|
|
|
|
|
2019-06-07 15:51:29 +02:00
|
|
|
/// Packages the kind of error we got from the const code interpreter
|
2019-11-26 22:19:54 -05:00
|
|
|
/// up with a Rust-level backtrace of where the error occurred.
|
2019-06-07 15:51:29 +02:00
|
|
|
/// Thsese should always be constructed by calling `.into()` on
|
2019-07-30 16:08:32 +05:30
|
|
|
/// a `InterpError`. In `librustc_mir::interpret`, we have `throw_err_*`
|
|
|
|
/// macros for this.
|
2019-12-01 11:42:19 +01:00
|
|
|
#[derive(Debug)]
|
2019-06-07 18:56:27 +02:00
|
|
|
pub struct InterpErrorInfo<'tcx> {
|
2019-07-24 10:24:55 +02:00
|
|
|
pub kind: InterpError<'tcx>,
|
2019-06-07 13:48:38 +02:00
|
|
|
backtrace: Option<Box<Backtrace>>,
|
2018-09-18 11:01:13 +02:00
|
|
|
}
|
|
|
|
|
2019-07-24 11:45:39 +02:00
|
|
|
impl fmt::Display for InterpErrorInfo<'_> {
|
2019-07-24 10:24:55 +02:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
write!(f, "{}", self.kind)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-24 11:45:39 +02:00
|
|
|
impl InterpErrorInfo<'_> {
|
2018-09-18 11:01:13 +02:00
|
|
|
pub fn print_backtrace(&mut self) {
|
|
|
|
if let Some(ref mut backtrace) = self.backtrace {
|
2018-12-11 15:53:35 +01:00
|
|
|
print_backtrace(&mut *backtrace);
|
2018-09-18 11:01:13 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-11 15:53:35 +01:00
|
|
|
fn print_backtrace(backtrace: &mut Backtrace) {
|
2018-09-18 11:01:13 +02:00
|
|
|
backtrace.resolve();
|
2018-12-11 15:53:35 +01:00
|
|
|
eprintln!("\n\nAn error occurred in miri:\n{:?}", backtrace);
|
2017-08-02 16:59:01 +02:00
|
|
|
}
|
|
|
|
|
2019-06-07 19:22:42 +02:00
|
|
|
impl From<ErrorHandled> for InterpErrorInfo<'tcx> {
|
|
|
|
fn from(err: ErrorHandled) -> Self {
|
|
|
|
match err {
|
|
|
|
ErrorHandled::Reported => err_inval!(ReferencedConstant),
|
|
|
|
ErrorHandled::TooGeneric => err_inval!(TooGeneric),
|
2019-12-22 17:42:04 -05:00
|
|
|
}
|
|
|
|
.into()
|
2019-06-07 19:22:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-24 10:24:55 +02:00
|
|
|
impl<'tcx> From<InterpError<'tcx>> for InterpErrorInfo<'tcx> {
|
|
|
|
fn from(kind: InterpError<'tcx>) -> Self {
|
2019-08-10 16:37:40 +02:00
|
|
|
let backtrace = match env::var("RUSTC_CTFE_BACKTRACE") {
|
2019-02-28 22:43:53 +00:00
|
|
|
// Matching `RUST_BACKTRACE` -- we treat "0" the same as "not present".
|
2018-09-18 11:01:13 +02:00
|
|
|
Ok(ref val) if val != "0" => {
|
|
|
|
let mut backtrace = Backtrace::new_unresolved();
|
2018-06-03 03:01:06 +02:00
|
|
|
|
2018-09-18 11:01:13 +02:00
|
|
|
if val == "immediate" {
|
2019-02-28 22:43:53 +00:00
|
|
|
// Print it now.
|
2018-12-11 15:53:35 +01:00
|
|
|
print_backtrace(&mut backtrace);
|
2018-09-18 11:01:13 +02:00
|
|
|
None
|
|
|
|
} else {
|
|
|
|
Some(Box::new(backtrace))
|
2018-06-02 23:38:57 +02:00
|
|
|
}
|
2019-12-22 17:42:04 -05:00
|
|
|
}
|
2018-09-18 11:01:13 +02:00
|
|
|
_ => None,
|
|
|
|
};
|
2019-12-22 17:42:04 -05:00
|
|
|
InterpErrorInfo { kind, backtrace }
|
2017-08-02 16:59:01 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-17 08:58:51 +02:00
|
|
|
/// Error information for when the program we executed turned out not to actually be a valid
|
|
|
|
/// program. This cannot happen in stand-alone Miri, but it can happen during CTFE/ConstProp
|
|
|
|
/// where we work on generic code or execution does not have all information available.
|
2019-07-26 15:28:27 +05:30
|
|
|
pub enum InvalidProgramInfo<'tcx> {
|
2019-07-29 20:17:52 +05:30
|
|
|
/// Resolution can fail if we are in a too generic context.
|
2019-07-25 16:59:38 +05:30
|
|
|
TooGeneric,
|
|
|
|
/// Cannot compute this constant because it depends on another one
|
2019-07-29 20:17:52 +05:30
|
|
|
/// which already produced an error.
|
2019-07-25 16:59:38 +05:30
|
|
|
ReferencedConstant,
|
2019-07-29 20:17:52 +05:30
|
|
|
/// Abort in case type errors are reached.
|
2019-07-25 16:59:38 +05:30
|
|
|
TypeckError,
|
2019-07-26 19:08:12 +05:30
|
|
|
/// An error occurred during layout computation.
|
2019-07-26 15:28:27 +05:30
|
|
|
Layout(layout::LayoutError<'tcx>),
|
2019-07-25 16:59:38 +05:30
|
|
|
}
|
|
|
|
|
2019-07-27 17:49:12 +05:30
|
|
|
impl fmt::Debug for InvalidProgramInfo<'tcx> {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
use InvalidProgramInfo::*;
|
|
|
|
match self {
|
2019-12-22 17:42:04 -05:00
|
|
|
TooGeneric => write!(f, "encountered overly generic constant"),
|
|
|
|
ReferencedConstant => write!(f, "referenced constant has errors"),
|
|
|
|
TypeckError => write!(f, "encountered constants with type errors, stopping evaluation"),
|
|
|
|
Layout(ref err) => write!(f, "{}", err),
|
2019-07-27 17:49:12 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-17 08:58:51 +02:00
|
|
|
/// Error information for when the program caused Undefined Behavior.
|
2019-08-02 23:24:27 +02:00
|
|
|
pub enum UndefinedBehaviorInfo {
|
2019-08-03 20:36:05 +02:00
|
|
|
/// Free-form case. Only for errors that are never caught!
|
2019-07-26 19:08:12 +05:30
|
|
|
Ub(String),
|
2019-08-03 20:36:05 +02:00
|
|
|
/// Free-form case for experimental UB. Only for errors that are never caught!
|
|
|
|
UbExperimental(String),
|
2019-07-27 17:49:12 +05:30
|
|
|
/// Unreachable code was executed.
|
2019-07-26 15:28:27 +05:30
|
|
|
Unreachable,
|
2019-10-09 06:08:46 -04:00
|
|
|
/// An enum discriminant was set to a value which was outside the range of valid values.
|
|
|
|
InvalidDiscriminant(ScalarMaybeUndef),
|
2019-12-01 12:08:05 +01:00
|
|
|
/// A slice/array index projection went out-of-bounds.
|
|
|
|
BoundsCheckFailed { len: u64, index: u64 },
|
|
|
|
/// Something was divided by 0 (x / 0).
|
|
|
|
DivisionByZero,
|
|
|
|
/// Something was "remainded" by 0 (x % 0).
|
|
|
|
RemainderByZero,
|
|
|
|
/// Overflowing inbounds pointer arithmetic.
|
|
|
|
PointerArithOverflow,
|
2019-07-26 10:51:54 +05:30
|
|
|
}
|
|
|
|
|
2019-08-02 23:24:27 +02:00
|
|
|
impl fmt::Debug for UndefinedBehaviorInfo {
|
2019-07-27 17:49:12 +05:30
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
2019-08-02 23:24:27 +02:00
|
|
|
use UndefinedBehaviorInfo::*;
|
2019-07-27 17:49:12 +05:30
|
|
|
match self {
|
2019-12-22 17:42:04 -05:00
|
|
|
Ub(msg) | UbExperimental(msg) => write!(f, "{}", msg),
|
|
|
|
Unreachable => write!(f, "entering unreachable code"),
|
|
|
|
InvalidDiscriminant(val) => write!(f, "encountering invalid enum discriminant {}", val),
|
|
|
|
BoundsCheckFailed { ref len, ref index } => write!(
|
|
|
|
f,
|
|
|
|
"indexing out of bounds: the len is {:?} but the index is {:?}",
|
|
|
|
len, index
|
|
|
|
),
|
|
|
|
DivisionByZero => write!(f, "dividing by zero"),
|
|
|
|
RemainderByZero => write!(f, "calculating the remainder with a divisor of zero"),
|
|
|
|
PointerArithOverflow => write!(f, "overflowing in-bounds pointer arithmetic"),
|
2019-07-27 17:49:12 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-17 08:58:51 +02:00
|
|
|
/// Error information for when the program did something that might (or might not) be correct
|
|
|
|
/// to do according to the Rust spec, but due to limitations in the interpreter, the
|
|
|
|
/// operation could not be carried out. These limitations can differ between CTFE and the
|
|
|
|
/// Miri engine, e.g., CTFE does not support casting pointers to "real" integers.
|
|
|
|
///
|
|
|
|
/// Currently, we also use this as fall-back error kind for errors that have not been
|
|
|
|
/// categorized yet.
|
2019-07-29 20:17:52 +05:30
|
|
|
pub enum UnsupportedOpInfo<'tcx> {
|
2019-08-03 20:36:05 +02:00
|
|
|
/// Free-form case. Only for errors that are never caught!
|
2019-08-02 23:41:24 +02:00
|
|
|
Unsupported(String),
|
2019-07-27 17:49:12 +05:30
|
|
|
|
2019-11-28 09:03:00 +01:00
|
|
|
/// When const-prop encounters a situation it does not support, it raises this error.
|
2020-03-04 08:40:13 +01:00
|
|
|
/// This must not allocate for performance reasons (hence `str`, not `String`).
|
2019-11-28 09:03:00 +01:00
|
|
|
ConstPropUnsupported(&'tcx str),
|
|
|
|
|
2019-09-17 08:58:51 +02:00
|
|
|
// -- Everything below is not categorized yet --
|
2019-07-26 15:28:27 +05:30
|
|
|
FunctionAbiMismatch(Abi, Abi),
|
|
|
|
FunctionArgMismatch(Ty<'tcx>, Ty<'tcx>),
|
|
|
|
FunctionRetMismatch(Ty<'tcx>, Ty<'tcx>),
|
|
|
|
FunctionArgCountMismatch,
|
|
|
|
UnterminatedCString(Pointer),
|
|
|
|
DanglingPointerDeref,
|
|
|
|
DoubleFree,
|
|
|
|
InvalidMemoryAccess,
|
|
|
|
InvalidFunctionPointer,
|
|
|
|
InvalidBool,
|
|
|
|
PointerOutOfBounds {
|
|
|
|
ptr: Pointer,
|
|
|
|
msg: CheckInAllocMsg,
|
|
|
|
allocation_size: Size,
|
|
|
|
},
|
|
|
|
InvalidNullPointerUsage,
|
|
|
|
ReadPointerAsBytes,
|
|
|
|
ReadBytesAsPointer,
|
|
|
|
ReadForeignStatic,
|
|
|
|
InvalidPointerMath,
|
|
|
|
ReadUndefBytes(Size),
|
|
|
|
DeadLocal,
|
|
|
|
InvalidBoolOp(mir::BinOp),
|
|
|
|
UnimplementedTraitSelection,
|
|
|
|
CalledClosureAsFunction,
|
|
|
|
NoMirFor(String),
|
2016-06-13 11:39:15 +02:00
|
|
|
DerefFunctionPointer,
|
|
|
|
ExecuteMemory,
|
2017-01-12 08:28:42 +01:00
|
|
|
InvalidChar(u128),
|
2017-05-25 16:40:13 -07:00
|
|
|
OutOfTls,
|
|
|
|
TlsOutOfBounds,
|
2016-07-05 14:27:27 +02:00
|
|
|
AlignmentCheckFailed {
|
2018-09-09 01:16:45 +03:00
|
|
|
required: Align,
|
|
|
|
has: Align,
|
2016-07-05 14:27:27 +02:00
|
|
|
},
|
2017-07-13 20:08:35 -07:00
|
|
|
ValidationFailure(String),
|
2016-09-09 12:51:14 +02:00
|
|
|
VtableForArgumentlessMethod,
|
2016-09-09 17:44:04 +02:00
|
|
|
ModifiedConstantMemory,
|
2018-11-19 13:49:07 +01:00
|
|
|
ModifiedStatic,
|
2016-11-03 12:30:41 +01:00
|
|
|
TypeNotPrimitive(Ty<'tcx>),
|
2017-07-28 16:48:43 +02:00
|
|
|
ReallocatedWrongMemoryKind(String, String),
|
|
|
|
DeallocatedWrongMemoryKind(String, String),
|
2017-07-03 16:06:06 -07:00
|
|
|
ReallocateNonBasePtr,
|
|
|
|
DeallocateNonBasePtr,
|
2018-09-09 01:16:45 +03:00
|
|
|
IncorrectAllocationInformation(Size, Size, Align, Align),
|
2017-06-23 12:55:49 +02:00
|
|
|
HeapAllocZeroBytes,
|
|
|
|
HeapAllocNonPowerOfTwoAlignment(u64),
|
2017-06-28 13:37:23 +02:00
|
|
|
ReadFromReturnPointer,
|
2017-07-12 10:36:14 +02:00
|
|
|
PathNotFound(Vec<String>),
|
2019-12-14 00:19:24 +01:00
|
|
|
TransmuteSizeDiff(Ty<'tcx>, Ty<'tcx>),
|
2016-03-14 21:48:00 -06:00
|
|
|
}
|
|
|
|
|
2019-07-29 20:17:52 +05:30
|
|
|
impl fmt::Debug for UnsupportedOpInfo<'tcx> {
|
2018-09-18 11:01:13 +02:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
2019-07-29 20:17:52 +05:30
|
|
|
use UnsupportedOpInfo::*;
|
2019-07-28 20:07:33 +05:30
|
|
|
match self {
|
2019-12-22 17:42:04 -05:00
|
|
|
PointerOutOfBounds { ptr, msg, allocation_size } => write!(
|
|
|
|
f,
|
|
|
|
"{} failed: pointer must be in-bounds at offset {}, \
|
2019-09-01 18:09:59 +01:00
|
|
|
but is outside bounds of allocation {} which has size {}",
|
2019-12-22 17:42:04 -05:00
|
|
|
msg,
|
|
|
|
ptr.offset.bytes(),
|
|
|
|
ptr.alloc_id,
|
|
|
|
allocation_size.bytes()
|
|
|
|
),
|
|
|
|
ValidationFailure(ref err) => write!(f, "type validation failed: {}", err),
|
2019-09-01 18:09:59 +01:00
|
|
|
NoMirFor(ref func) => write!(f, "no MIR for `{}`", func),
|
2019-12-22 17:42:04 -05:00
|
|
|
FunctionAbiMismatch(caller_abi, callee_abi) => write!(
|
|
|
|
f,
|
|
|
|
"tried to call a function with ABI {:?} using caller ABI {:?}",
|
|
|
|
callee_abi, caller_abi
|
|
|
|
),
|
|
|
|
FunctionArgMismatch(caller_ty, callee_ty) => write!(
|
|
|
|
f,
|
|
|
|
"tried to call a function with argument of type {:?} \
|
2018-08-27 13:34:35 +02:00
|
|
|
passing data of type {:?}",
|
2019-12-22 17:42:04 -05:00
|
|
|
callee_ty, caller_ty
|
|
|
|
),
|
2019-12-14 00:19:24 +01:00
|
|
|
TransmuteSizeDiff(from_ty, to_ty) => write!(
|
|
|
|
f,
|
|
|
|
"tried to transmute from {:?} to {:?}, but their sizes differed",
|
|
|
|
from_ty, to_ty
|
|
|
|
),
|
2019-12-22 17:42:04 -05:00
|
|
|
FunctionRetMismatch(caller_ty, callee_ty) => write!(
|
|
|
|
f,
|
|
|
|
"tried to call a function with return type {:?} \
|
2018-10-02 21:16:35 +02:00
|
|
|
passing return place of type {:?}",
|
2019-12-22 17:42:04 -05:00
|
|
|
callee_ty, caller_ty
|
|
|
|
),
|
|
|
|
FunctionArgCountMismatch => {
|
|
|
|
write!(f, "tried to call a function with incorrect number of arguments")
|
|
|
|
}
|
|
|
|
ReallocatedWrongMemoryKind(ref old, ref new) => {
|
|
|
|
write!(f, "tried to reallocate memory from `{}` to `{}`", old, new)
|
|
|
|
}
|
|
|
|
DeallocatedWrongMemoryKind(ref old, ref new) => {
|
|
|
|
write!(f, "tried to deallocate `{}` memory but gave `{}` as the kind", old, new)
|
|
|
|
}
|
|
|
|
InvalidChar(c) => {
|
|
|
|
write!(f, "tried to interpret an invalid 32-bit value as a char: {}", c)
|
|
|
|
}
|
|
|
|
AlignmentCheckFailed { required, has } => write!(
|
|
|
|
f,
|
|
|
|
"tried to access memory with alignment {}, but alignment {} is required",
|
|
|
|
has.bytes(),
|
|
|
|
required.bytes()
|
|
|
|
),
|
|
|
|
TypeNotPrimitive(ty) => write!(f, "expected primitive type, got {}", ty),
|
|
|
|
PathNotFound(ref path) => write!(f, "cannot find path {:?}", path),
|
|
|
|
IncorrectAllocationInformation(size, size2, align, align2) => write!(
|
|
|
|
f,
|
|
|
|
"incorrect alloc info: expected size {} and align {}, \
|
2018-09-09 00:22:22 +03:00
|
|
|
got size {} and align {}",
|
2019-12-22 17:42:04 -05:00
|
|
|
size.bytes(),
|
|
|
|
align.bytes(),
|
|
|
|
size2.bytes(),
|
|
|
|
align2.bytes()
|
|
|
|
),
|
|
|
|
InvalidMemoryAccess => write!(f, "tried to access memory through an invalid pointer"),
|
|
|
|
DanglingPointerDeref => write!(f, "dangling pointer was dereferenced"),
|
|
|
|
DoubleFree => write!(f, "tried to deallocate dangling pointer"),
|
|
|
|
InvalidFunctionPointer => {
|
|
|
|
write!(f, "tried to use a function pointer after offsetting it")
|
|
|
|
}
|
|
|
|
InvalidBool => write!(f, "invalid boolean value read"),
|
|
|
|
InvalidNullPointerUsage => write!(f, "invalid use of NULL pointer"),
|
|
|
|
ReadPointerAsBytes => write!(
|
|
|
|
f,
|
|
|
|
"a raw memory access tried to access part of a pointer value as raw \
|
|
|
|
bytes"
|
|
|
|
),
|
|
|
|
ReadBytesAsPointer => {
|
|
|
|
write!(f, "a memory access tried to interpret some bytes as a pointer")
|
|
|
|
}
|
|
|
|
ReadForeignStatic => write!(f, "tried to read from foreign (extern) static"),
|
|
|
|
InvalidPointerMath => write!(
|
|
|
|
f,
|
|
|
|
"attempted to do invalid arithmetic on pointers that would leak base \
|
|
|
|
addresses, e.g., comparing pointers into different allocations"
|
|
|
|
),
|
|
|
|
DeadLocal => write!(f, "tried to access a dead local variable"),
|
|
|
|
DerefFunctionPointer => write!(f, "tried to dereference a function pointer"),
|
|
|
|
ExecuteMemory => write!(f, "tried to treat a memory pointer as a function pointer"),
|
|
|
|
OutOfTls => write!(f, "reached the maximum number of representable TLS keys"),
|
|
|
|
TlsOutOfBounds => write!(f, "accessed an invalid (unallocated) TLS key"),
|
|
|
|
CalledClosureAsFunction => {
|
|
|
|
write!(f, "tried to call a closure through a function pointer")
|
|
|
|
}
|
|
|
|
VtableForArgumentlessMethod => {
|
|
|
|
write!(f, "tried to call a vtable function without arguments")
|
|
|
|
}
|
|
|
|
ModifiedConstantMemory => write!(f, "tried to modify constant memory"),
|
|
|
|
ModifiedStatic => write!(
|
|
|
|
f,
|
|
|
|
"tried to modify a static's initial value from another static's \
|
|
|
|
initializer"
|
|
|
|
),
|
|
|
|
ReallocateNonBasePtr => write!(
|
|
|
|
f,
|
|
|
|
"tried to reallocate with a pointer not to the beginning of an \
|
|
|
|
existing object"
|
|
|
|
),
|
|
|
|
DeallocateNonBasePtr => write!(
|
|
|
|
f,
|
|
|
|
"tried to deallocate with a pointer not to the beginning of an \
|
|
|
|
existing object"
|
|
|
|
),
|
|
|
|
HeapAllocZeroBytes => write!(f, "tried to re-, de- or allocate zero bytes on the heap"),
|
|
|
|
ReadFromReturnPointer => write!(f, "tried to read from the return pointer"),
|
|
|
|
UnimplementedTraitSelection => {
|
|
|
|
write!(f, "there were unresolved type arguments during trait selection")
|
|
|
|
}
|
|
|
|
InvalidBoolOp(_) => write!(f, "invalid boolean operation"),
|
|
|
|
UnterminatedCString(_) => write!(
|
|
|
|
f,
|
|
|
|
"attempted to get length of a null-terminated string, but no null \
|
|
|
|
found before end of allocation"
|
|
|
|
),
|
|
|
|
ReadUndefBytes(_) => write!(f, "attempted to read undefined bytes"),
|
|
|
|
HeapAllocNonPowerOfTwoAlignment(_) => write!(
|
|
|
|
f,
|
|
|
|
"tried to re-, de-, or allocate heap memory with alignment that is \
|
|
|
|
not a power of two"
|
|
|
|
),
|
|
|
|
Unsupported(ref msg) => write!(f, "{}", msg),
|
|
|
|
ConstPropUnsupported(ref msg) => {
|
|
|
|
write!(f, "Constant propagation encountered an unsupported situation: {}", msg)
|
|
|
|
}
|
2019-07-28 20:07:33 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-17 08:58:51 +02:00
|
|
|
/// Error information for when the program exhausted the resources granted to it
|
|
|
|
/// by the interpreter.
|
2019-07-28 20:07:33 +05:30
|
|
|
pub enum ResourceExhaustionInfo {
|
2019-07-31 12:48:54 +05:30
|
|
|
/// The stack grew too big.
|
2019-07-28 20:07:33 +05:30
|
|
|
StackFrameLimitReached,
|
2019-07-31 12:48:54 +05:30
|
|
|
/// The program ran into an infinite loop.
|
2019-07-28 20:07:33 +05:30
|
|
|
InfiniteLoop,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Debug for ResourceExhaustionInfo {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
use ResourceExhaustionInfo::*;
|
|
|
|
match self {
|
2019-12-22 17:42:04 -05:00
|
|
|
StackFrameLimitReached => {
|
|
|
|
write!(f, "reached the configured maximum number of stack frames")
|
|
|
|
}
|
|
|
|
InfiniteLoop => write!(
|
|
|
|
f,
|
|
|
|
"duplicate interpreter state observed here, const evaluation will never \
|
|
|
|
terminate"
|
|
|
|
),
|
2019-07-28 20:07:33 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub enum InterpError<'tcx> {
|
|
|
|
/// The program caused undefined behavior.
|
2019-08-02 23:24:27 +02:00
|
|
|
UndefinedBehavior(UndefinedBehaviorInfo),
|
2019-07-28 20:07:33 +05:30
|
|
|
/// The program did something the interpreter does not support (some of these *might* be UB
|
|
|
|
/// but the interpreter is not sure).
|
2019-07-29 20:17:52 +05:30
|
|
|
Unsupported(UnsupportedOpInfo<'tcx>),
|
2019-12-01 11:42:19 +01:00
|
|
|
/// The program was invalid (ill-typed, bad MIR, not sufficiently monomorphized, ...).
|
2019-07-28 20:07:33 +05:30
|
|
|
InvalidProgram(InvalidProgramInfo<'tcx>),
|
|
|
|
/// The program exhausted the interpreter's resources (stack/heap too big,
|
2019-12-01 11:42:19 +01:00
|
|
|
/// execution takes too long, ...).
|
2019-07-28 20:07:33 +05:30
|
|
|
ResourceExhaustion(ResourceExhaustionInfo),
|
2019-12-01 11:42:19 +01:00
|
|
|
/// Stop execution for a machine-controlled reason. This is never raised by
|
|
|
|
/// the core engine itself.
|
|
|
|
MachineStop(Box<dyn Any + Send>),
|
2019-07-28 20:07:33 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
pub type InterpResult<'tcx, T = ()> = Result<T, InterpErrorInfo<'tcx>>;
|
|
|
|
|
|
|
|
impl fmt::Display for InterpError<'_> {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
2019-09-06 03:57:44 +01:00
|
|
|
// Forward `Display` to `Debug`.
|
2019-07-28 20:07:33 +05:30
|
|
|
write!(f, "{:?}", self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Debug for InterpError<'_> {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
use InterpError::*;
|
|
|
|
match *self {
|
2019-12-22 17:42:04 -05:00
|
|
|
Unsupported(ref msg) => write!(f, "{:?}", msg),
|
|
|
|
InvalidProgram(ref msg) => write!(f, "{:?}", msg),
|
|
|
|
UndefinedBehavior(ref msg) => write!(f, "{:?}", msg),
|
|
|
|
ResourceExhaustion(ref msg) => write!(f, "{:?}", msg),
|
2020-02-08 22:21:20 +01:00
|
|
|
MachineStop(_) => bug!("unhandled MachineStop"),
|
2018-04-26 11:37:03 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-03-04 08:40:13 +01:00
|
|
|
|
|
|
|
impl InterpError<'_> {
|
|
|
|
/// Some errors allocate to be created as they contain free-from strings.
|
|
|
|
/// And sometiems we want to be sure that did not happen as it is a
|
|
|
|
/// waste of resources.
|
|
|
|
pub fn allocates(&self) -> bool {
|
|
|
|
match self {
|
|
|
|
InterpError::MachineStop(_)
|
|
|
|
| InterpError::Unsupported(UnsupportedOpInfo::Unsupported(_))
|
|
|
|
| InterpError::Unsupported(UnsupportedOpInfo::ValidationFailure(_))
|
|
|
|
| InterpError::UndefinedBehavior(UndefinedBehaviorInfo::Ub(_))
|
|
|
|
| InterpError::UndefinedBehavior(UndefinedBehaviorInfo::UbExperimental(_)) => true,
|
|
|
|
_ => false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|