rust/src/librustc/mir/interpret/error.rs

508 lines
19 KiB
Rust
Raw Normal View History

use std::{fmt, env};
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;
use crate::ty::{self, Ty, layout};
use crate::ty::layout::{Size, Align, LayoutError};
use rustc_target::spec::abi::Abi;
use super::{RawConst, Pointer, InboundsCheck, ScalarMaybeUndef};
use backtrace::Backtrace;
2016-03-14 21:48:00 -06:00
2019-02-05 11:20:45 -06:00
use crate::ty::query::TyCtxtAt;
use crate::errors::DiagnosticBuilder;
2018-11-14 23:14:57 +01:00
use syntax_pos::{Pos, Span};
use syntax::ast;
use syntax::symbol::Symbol;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum ErrorHandled {
/// Already reported a lint or an error for this evaluation
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 {
ErrorHandled::Reported => {},
ErrorHandled::TooGeneric => bug!("MIR interpretation failed without reporting an error \
even though it was fully monomorphized"),
}
}
}
pub type ConstEvalRawResult<'tcx> = Result<RawConst<'tcx>, ErrorHandled>;
2018-12-13 11:11:12 +01:00
pub type ConstEvalResult<'tcx> = Result<ty::Const<'tcx>, ErrorHandled>;
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct ConstEvalErr<'tcx> {
pub span: Span,
2019-02-05 11:20:45 -06:00
pub error: crate::mir::interpret::EvalErrorKind<'tcx, u64>,
2018-11-14 17:25:06 +01:00
pub stacktrace: Vec<FrameInfo<'tcx>>,
}
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
2018-11-14 17:25:06 +01:00
pub struct FrameInfo<'tcx> {
pub call_site: Span, // this span is in the caller!
2018-11-14 17:25:06 +01:00
pub instance: ty::Instance<'tcx>,
pub lint_root: Option<ast::NodeId>,
}
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
}
if !self.call_site.is_dummy() {
let lo = tcx.sess.source_map().lookup_char_pos_adj(self.call_site.lo());
2018-11-14 23:14:57 +01:00
write!(f, " at {}:{}:{}", lo.filename, lo.line, lo.col.to_usize() + 1)?;
}
Ok(())
2018-11-14 17:25:06 +01:00
})
}
}
impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
pub fn struct_error(&self,
tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
message: &str)
-> Result<DiagnosticBuilder<'tcx>, ErrorHandled>
{
self.struct_generic(tcx, message, None)
}
pub fn report_as_error(&self,
tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
message: &str
) -> ErrorHandled {
2018-06-04 18:32:06 +02:00
let err = self.struct_error(tcx, message);
match err {
Ok(mut err) => {
err.emit();
ErrorHandled::Reported
},
Err(err) => err,
}
}
pub fn report_as_lint(&self,
tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
message: &str,
lint_root: ast::NodeId,
) -> ErrorHandled {
let lint = self.struct_generic(
tcx,
message,
Some(lint_root),
);
match lint {
Ok(mut lint) => {
lint.emit();
ErrorHandled::Reported
},
Err(err) => err,
}
}
fn struct_generic(
&self,
tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
message: &str,
lint_root: Option<ast::NodeId>,
) -> Result<DiagnosticBuilder<'tcx>, ErrorHandled> {
match self.error {
EvalErrorKind::Layout(LayoutError::Unknown(_)) |
EvalErrorKind::TooGeneric => return Err(ErrorHandled::TooGeneric),
EvalErrorKind::Layout(LayoutError::SizeOverflow(_)) |
EvalErrorKind::TypeckError => return Err(ErrorHandled::Reported),
_ => {},
}
trace!("reporting const eval failure at {:?}", self.span);
let mut err = if let Some(lint_root) = lint_root {
let node_id = self.stacktrace
.iter()
.rev()
.filter_map(|frame| frame.lint_root)
.next()
.unwrap_or(lint_root);
tcx.struct_span_lint_node(
2019-02-05 11:20:45 -06:00
crate::rustc::lint::builtin::CONST_ERR,
node_id,
tcx.span,
message,
)
} else {
struct_error(tcx, message)
};
err.span_label(self.span, self.error.to_string());
2018-11-14 17:25:06 +01: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.
if self.stacktrace.len() > 0 {
for frame_info in &self.stacktrace[..self.stacktrace.len()-1] {
err.span_label(frame_info.call_site, frame_info.to_string());
2018-11-14 17:25:06 +01:00
}
}
Ok(err)
}
}
pub fn struct_error<'a, 'gcx, 'tcx>(
tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
msg: &str,
) -> DiagnosticBuilder<'tcx> {
struct_span_err!(tcx.sess, tcx.span, E0080, "{}", msg)
}
#[derive(Debug, Clone)]
2017-08-02 16:59:01 +02:00
pub struct EvalError<'tcx> {
pub kind: EvalErrorKind<'tcx, u64>,
pub backtrace: Option<Box<Backtrace>>,
}
impl<'tcx> EvalError<'tcx> {
pub fn print_backtrace(&mut self) {
if let Some(ref mut backtrace) = self.backtrace {
print_backtrace(&mut *backtrace);
}
}
}
fn print_backtrace(backtrace: &mut Backtrace) {
backtrace.resolve();
eprintln!("\n\nAn error occurred in miri:\n{:?}", backtrace);
2017-08-02 16:59:01 +02:00
}
2018-06-03 03:01:06 +02:00
impl<'tcx> From<EvalErrorKind<'tcx, u64>> for EvalError<'tcx> {
fn from(kind: EvalErrorKind<'tcx, u64>) -> Self {
let backtrace = match env::var("RUST_CTFE_BACKTRACE") {
// matching RUST_BACKTRACE, we treat "0" the same as "not present".
Ok(ref val) if val != "0" => {
let mut backtrace = Backtrace::new_unresolved();
2018-06-03 03:01:06 +02:00
if val == "immediate" {
// Print it now
print_backtrace(&mut backtrace);
None
} else {
Some(Box::new(backtrace))
2018-06-02 23:38:57 +02:00
}
2018-06-03 03:01:06 +02:00
},
_ => None,
};
2017-08-02 16:59:01 +02:00
EvalError {
2018-01-31 10:39:30 +01:00
kind,
backtrace,
2017-08-02 16:59:01 +02:00
}
}
}
pub type AssertMessage<'tcx> = EvalErrorKind<'tcx, mir::Operand<'tcx>>;
#[derive(Clone, RustcEncodable, RustcDecodable)]
pub enum EvalErrorKind<'tcx, O> {
/// This variant is used by machines to signal their own errors that do not
/// match an existing variant
MachineError(String),
FunctionAbiMismatch(Abi, Abi),
FunctionArgMismatch(Ty<'tcx>, Ty<'tcx>),
FunctionRetMismatch(Ty<'tcx>, Ty<'tcx>),
FunctionArgCountMismatch,
NoMirFor(String),
2018-05-21 00:37:44 +02:00
UnterminatedCString(Pointer),
2016-03-14 21:48:00 -06:00
DanglingPointerDeref,
DoubleFree,
2016-09-22 15:47:16 +02:00
InvalidMemoryAccess,
2016-06-08 13:43:34 +02:00
InvalidFunctionPointer,
2016-03-14 21:48:00 -06:00
InvalidBool,
InvalidDiscriminant(ScalarMaybeUndef),
2016-05-31 12:05:25 +02:00
PointerOutOfBounds {
2018-05-21 00:37:44 +02:00
ptr: Pointer,
check: InboundsCheck,
allocation_size: Size,
2016-05-31 12:05:25 +02:00
},
InvalidNullPointerUsage,
ReadPointerAsBytes,
2017-06-19 10:58:59 +02:00
ReadBytesAsPointer,
ReadForeignStatic,
InvalidPointerMath,
ReadUndefBytes(Size),
DeadLocal,
2016-05-30 15:27:52 +02:00
InvalidBoolOp(mir::BinOp),
Unimplemented(String),
DerefFunctionPointer,
ExecuteMemory,
BoundsCheck { len: O, index: O },
Overflow(mir::BinOp),
OverflowNeg,
DivisionByZero,
RemainderByZero,
2017-06-22 00:08:19 -07:00
Intrinsic(String),
2017-01-12 08:28:42 +01:00
InvalidChar(u128),
2016-07-05 13:23:58 +02:00
StackFrameLimitReached,
2017-05-25 16:40:13 -07:00
OutOfTls,
TlsOutOfBounds,
2017-05-25 22:38:07 -07:00
AbiViolation(String),
AlignmentCheckFailed {
required: Align,
has: Align,
},
ValidationFailure(String),
CalledClosureAsFunction,
VtableForArgumentlessMethod,
ModifiedConstantMemory,
ModifiedStatic,
2016-09-13 13:08:57 +02:00
AssumptionNotHeld,
2016-09-28 11:48:43 -06:00
InlineAsm,
TypeNotPrimitive(Ty<'tcx>),
ReallocatedWrongMemoryKind(String, String),
DeallocatedWrongMemoryKind(String, String),
ReallocateNonBasePtr,
DeallocateNonBasePtr,
IncorrectAllocationInformation(Size, Size, Align, Align),
Layout(layout::LayoutError<'tcx>),
2017-06-23 12:55:49 +02:00
HeapAllocZeroBytes,
HeapAllocNonPowerOfTwoAlignment(u64),
Unreachable,
Panic {
msg: Symbol,
line: u32,
col: u32,
file: Symbol,
},
ReadFromReturnPointer,
PathNotFound(Vec<String>),
2017-12-06 09:25:29 +01:00
UnimplementedTraitSelection,
/// Abort in case type errors are reached
TypeckError,
2018-06-19 16:40:53 +02:00
/// Resolution can fail if we are in a too generic context
2018-06-25 15:08:05 +02:00
TooGeneric,
2018-01-31 15:06:45 +01:00
/// Cannot compute this constant because it depends on another one
/// which already produced an error
ReferencedConstant,
GeneratorResumedAfterReturn,
GeneratorResumedAfterPanic,
InfiniteLoop,
2016-03-14 21:48:00 -06:00
}
pub type EvalResult<'tcx, T = ()> = Result<T, EvalError<'tcx>>;
2016-03-14 21:48:00 -06:00
impl<'tcx, O> EvalErrorKind<'tcx, O> {
pub fn description(&self) -> &str {
2017-08-02 16:59:01 +02:00
use self::EvalErrorKind::*;
match *self {
MachineError(ref inner) => inner,
FunctionAbiMismatch(..) | FunctionArgMismatch(..) | FunctionRetMismatch(..)
| FunctionArgCountMismatch =>
"tried to call a function through a function pointer of incompatible type",
InvalidMemoryAccess =>
2016-09-22 15:47:16 +02:00
"tried to access memory through an invalid pointer",
DanglingPointerDeref =>
"dangling pointer was dereferenced",
DoubleFree =>
"tried to deallocate dangling pointer",
InvalidFunctionPointer =>
"tried to use a function pointer after offsetting it",
InvalidBool =>
"invalid boolean value read",
2018-08-26 14:22:59 +02:00
InvalidDiscriminant(..) =>
"invalid enum discriminant value read",
PointerOutOfBounds { .. } =>
"pointer offset outside bounds of allocation",
InvalidNullPointerUsage =>
"invalid use of NULL pointer",
2017-07-13 17:25:38 -07:00
ValidationFailure(..) =>
"type validation failed",
ReadPointerAsBytes =>
"a raw memory access tried to access part of a pointer value as raw bytes",
ReadBytesAsPointer =>
2017-06-19 10:58:59 +02:00
"a memory access tried to interpret some bytes as a pointer",
ReadForeignStatic =>
2018-06-25 00:08:36 +01:00
"tried to read from foreign (extern) static",
InvalidPointerMath =>
2018-08-22 16:54:05 -03:00
"attempted to do invalid arithmetic on pointers that would leak base addresses, \
e.g., comparing pointers into different allocations",
ReadUndefBytes(_) =>
"attempted to read undefined bytes",
DeadLocal =>
"tried to access a dead local variable",
InvalidBoolOp(_) =>
2016-05-30 15:27:52 +02:00
"invalid boolean operation",
Unimplemented(ref msg) => msg,
DerefFunctionPointer =>
"tried to dereference a function pointer",
ExecuteMemory =>
"tried to treat a memory pointer as a function pointer",
BoundsCheck{..} =>
2016-06-17 13:09:20 +02:00
"array index out of bounds",
Intrinsic(..) =>
2017-06-22 00:08:19 -07:00
"intrinsic failed",
NoMirFor(..) =>
"mir not found",
InvalidChar(..) =>
2016-06-20 12:29:45 +02:00
"tried to interpret an invalid 32-bit value as a char",
StackFrameLimitReached =>
2016-07-05 13:23:58 +02:00
"reached the configured maximum number of stack frames",
OutOfTls =>
2017-05-25 16:40:13 -07:00
"reached the maximum number of representable TLS keys",
TlsOutOfBounds =>
2017-05-25 16:40:13 -07:00
"accessed an invalid (unallocated) TLS key",
AbiViolation(ref msg) => msg,
AlignmentCheckFailed{..} =>
"tried to execute a misaligned read or write",
CalledClosureAsFunction =>
"tried to call a closure through a function pointer",
VtableForArgumentlessMethod =>
"tried to call a vtable function without arguments",
ModifiedConstantMemory =>
"tried to modify constant memory",
ModifiedStatic =>
"tried to modify a static's initial value from another static's initializer",
AssumptionNotHeld =>
2016-09-28 18:22:25 +02:00
"`assume` argument was false",
InlineAsm =>
2017-02-10 05:27:02 -08:00
"miri does not support inline assembly",
TypeNotPrimitive(_) =>
"expected primitive type, got nonprimitive",
ReallocatedWrongMemoryKind(_, _) =>
2017-08-03 12:37:24 +02:00
"tried to reallocate memory from one kind to another",
DeallocatedWrongMemoryKind(_, _) =>
"tried to deallocate memory of the wrong kind",
ReallocateNonBasePtr =>
"tried to reallocate with a pointer not to the beginning of an existing object",
DeallocateNonBasePtr =>
"tried to deallocate with a pointer not to the beginning of an existing object",
2017-12-06 09:25:29 +01:00
IncorrectAllocationInformation(..) =>
"tried to deallocate or reallocate using incorrect alignment or size",
Layout(_) =>
"rustc layout computation failed",
UnterminatedCString(_) =>
2018-08-23 08:45:59 -07:00
"attempted to get length of a null terminated string, but no null found before end \
2018-08-22 16:54:05 -03:00
of allocation",
HeapAllocZeroBytes =>
2017-06-23 12:55:49 +02:00
"tried to re-, de- or allocate zero bytes on the heap",
HeapAllocNonPowerOfTwoAlignment(_) =>
2018-08-23 08:45:59 -07:00
"tried to re-, de-, or allocate heap memory with alignment that is not a power of \
2018-08-22 16:54:05 -03:00
two",
Unreachable =>
"entered unreachable code",
Panic { .. } =>
"the evaluated program panicked",
ReadFromReturnPointer =>
"tried to read from the return pointer",
PathNotFound(_) =>
"a path could not be resolved, maybe the crate is not loaded",
2017-12-06 09:25:29 +01:00
UnimplementedTraitSelection =>
"there were unresolved type arguments during trait selection",
TypeckError =>
"encountered constants with type errors, stopping evaluation",
2018-06-25 15:08:05 +02:00
TooGeneric =>
2018-06-19 16:40:53 +02:00
"encountered overly generic constant",
ReferencedConstant =>
2018-01-31 15:06:45 +01:00
"referenced constant has errors",
Overflow(mir::BinOp::Add) => "attempt to add with overflow",
Overflow(mir::BinOp::Sub) => "attempt to subtract with overflow",
Overflow(mir::BinOp::Mul) => "attempt to multiply with overflow",
Overflow(mir::BinOp::Div) => "attempt to divide with overflow",
Overflow(mir::BinOp::Rem) => "attempt to calculate the remainder with overflow",
OverflowNeg => "attempt to negate with overflow",
Overflow(mir::BinOp::Shr) => "attempt to shift right with overflow",
Overflow(mir::BinOp::Shl) => "attempt to shift left with overflow",
Overflow(op) => bug!("{:?} cannot overflow", op),
DivisionByZero => "attempt to divide by zero",
RemainderByZero => "attempt to calculate the remainder with a divisor of zero",
GeneratorResumedAfterReturn => "generator resumed after completion",
GeneratorResumedAfterPanic => "generator resumed after panicking",
InfiniteLoop =>
"duplicate interpreter state observed here, const evaluation will never terminate",
2016-03-14 21:48:00 -06:00
}
}
}
impl<'tcx> fmt::Display for EvalError<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.kind)
}
}
impl<'tcx> fmt::Display for EvalErrorKind<'tcx, u64> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self)
}
}
impl<'tcx, O: fmt::Debug> fmt::Debug for EvalErrorKind<'tcx, O> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2017-08-02 16:59:01 +02:00
use self::EvalErrorKind::*;
match *self {
PointerOutOfBounds { ptr, check, allocation_size } => {
write!(f, "Pointer must be in-bounds{} at offset {}, but is outside bounds of \
allocation {} which has size {}",
match check {
InboundsCheck::Live => " and live",
InboundsCheck::MaybeDead => "",
},
ptr.offset.bytes(), ptr.alloc_id, allocation_size.bytes())
2016-06-01 11:22:37 +02:00
},
2017-07-13 17:25:38 -07:00
ValidationFailure(ref err) => {
write!(f, "type validation failed: {}", err)
}
NoMirFor(ref func) => write!(f, "no mir for `{}`", func),
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 {:?} \
passing data of type {:?}",
callee_ty, caller_ty),
FunctionRetMismatch(caller_ty, callee_ty) =>
write!(f, "tried to call a function with return type {:?} \
passing return place of type {:?}",
callee_ty, caller_ty),
FunctionArgCountMismatch =>
write!(f, "tried to call a function with incorrect number of arguments"),
BoundsCheck { ref len, ref index } =>
write!(f, "index out of bounds: the len is {:?} but the index is {:?}", len, index),
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),
Intrinsic(ref err) =>
2017-06-22 00:08:19 -07:00
write!(f, "{}", err),
InvalidChar(c) =>
2016-06-21 09:43:27 +02:00
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),
Layout(ref err) =>
write!(f, "rustc layout computation failed: {:?}", err),
PathNotFound(ref path) =>
write!(f, "Cannot find path {:?}", path),
MachineError(ref inner) =>
2018-01-26 15:19:01 +01:00
write!(f, "{}", inner),
2017-12-06 09:25:29 +01:00
IncorrectAllocationInformation(size, size2, align, align2) =>
write!(f, "incorrect alloc info: expected size {} and align {}, \
got size {} and align {}",
size.bytes(), align.bytes(), size2.bytes(), align2.bytes()),
Panic { ref msg, line, col, ref file } =>
write!(f, "the evaluated program panicked at '{}', {}:{}:{}", msg, file, line, col),
2018-08-26 14:22:59 +02:00
InvalidDiscriminant(val) =>
write!(f, "encountered invalid enum discriminant {}", val),
_ => write!(f, "{}", self.description()),
2018-04-26 11:37:03 +02:00
}
}
}