2020-09-07 17:30:38 +02:00
|
|
|
use super::{AllocId, ConstAlloc, Pointer, Scalar};
|
2017-08-02 16:59:01 +02:00
|
|
|
|
2020-02-15 11:56:23 +13:00
|
|
|
use crate::mir::interpret::ConstValue;
|
2022-04-12 18:14:28 +02:00
|
|
|
use crate::ty::{layout, query::TyCtxtAt, tls, FnSig, Ty, ValTree};
|
2017-07-21 13:39:06 +02:00
|
|
|
|
2020-02-16 20:32:25 -05:00
|
|
|
use rustc_data_structures::sync::Lock;
|
2022-01-23 12:34:26 -06:00
|
|
|
use rustc_errors::{pluralize, struct_span_err, DiagnosticBuilder, ErrorGuaranteed};
|
2019-09-06 03:57:44 +01:00
|
|
|
use rustc_macros::HashStable;
|
2020-02-16 20:32:25 -05:00
|
|
|
use rustc_session::CtfeBacktrace;
|
2020-08-09 15:37:32 +02:00
|
|
|
use rustc_span::def_id::DefId;
|
2021-11-28 19:35:50 -05:00
|
|
|
use rustc_target::abi::{call, Align, Size};
|
2021-02-20 19:01:25 +01:00
|
|
|
use std::{any::Any, backtrace::Backtrace, fmt};
|
2019-09-06 03:57:44 +01:00
|
|
|
|
2020-06-11 15:49:57 +01:00
|
|
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
|
2018-08-26 15:19:34 +02:00
|
|
|
pub enum ErrorHandled {
|
2020-04-12 04:24:25 +03:00
|
|
|
/// Already reported an error for this evaluation, and the compilation is
|
|
|
|
/// *guaranteed* to fail. Warnings/lints *must not* produce `Reported`.
|
2022-01-23 12:34:26 -06:00
|
|
|
Reported(ErrorGuaranteed),
|
2020-04-12 04:24:25 +03:00
|
|
|
/// Already emitted a lint for this evaluation.
|
|
|
|
Linted,
|
2018-08-26 15:19:34 +02:00
|
|
|
/// Don't emit an error, the evaluation failed because the MIR was generic
|
|
|
|
/// and the substs didn't fully monomorphize it.
|
|
|
|
TooGeneric,
|
|
|
|
}
|
|
|
|
|
2022-01-23 12:34:26 -06:00
|
|
|
impl From<ErrorGuaranteed> for ErrorHandled {
|
|
|
|
fn from(err: ErrorGuaranteed) -> ErrorHandled {
|
2020-09-21 23:25:52 +02:00
|
|
|
ErrorHandled::Reported(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-17 11:05:17 +01:00
|
|
|
TrivialTypeTraversalAndLiftImpls! {
|
2019-05-31 10:23:22 +02:00
|
|
|
ErrorHandled,
|
|
|
|
}
|
|
|
|
|
2020-09-07 17:30:38 +02:00
|
|
|
pub type EvalToAllocationRawResult<'tcx> = Result<ConstAlloc<'tcx>, ErrorHandled>;
|
2020-08-20 18:55:07 +02:00
|
|
|
pub type EvalToConstValueResult<'tcx> = Result<ConstValue<'tcx>, ErrorHandled>;
|
2022-04-12 18:14:28 +02:00
|
|
|
pub type EvalToValTreeResult<'tcx> = Result<Option<ValTree<'tcx>>, ErrorHandled>;
|
2018-06-25 18:46:02 +02:00
|
|
|
|
2022-01-27 09:44:25 +00:00
|
|
|
pub fn struct_error<'tcx>(
|
|
|
|
tcx: TyCtxtAt<'tcx>,
|
|
|
|
msg: &str,
|
2022-01-23 12:34:26 -06:00
|
|
|
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
|
2018-06-25 18:46:02 +02:00
|
|
|
struct_span_err!(tcx.sess, tcx.span, E0080, "{}", msg)
|
|
|
|
}
|
|
|
|
|
2021-03-06 16:02:48 +00:00
|
|
|
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
|
2021-02-14 00:00:00 +00:00
|
|
|
static_assert_size!(InterpErrorInfo<'_>, 8);
|
|
|
|
|
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.
|
2021-04-19 15:57:08 +03:00
|
|
|
/// These should always be constructed by calling `.into()` on
|
2021-08-22 14:46:15 +02:00
|
|
|
/// an `InterpError`. In `rustc_mir::interpret`, we have `throw_err_*`
|
2019-07-30 16:08:32 +05:30
|
|
|
/// macros for this.
|
2019-12-01 11:42:19 +01:00
|
|
|
#[derive(Debug)]
|
2021-02-14 00:00:00 +00:00
|
|
|
pub struct InterpErrorInfo<'tcx>(Box<InterpErrorInfoInner<'tcx>>);
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
struct InterpErrorInfoInner<'tcx> {
|
|
|
|
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 {
|
2021-02-14 00:00:00 +00:00
|
|
|
write!(f, "{}", self.0.kind)
|
2019-07-24 10:24:55 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-15 19:32:30 -05:00
|
|
|
impl<'tcx> InterpErrorInfo<'tcx> {
|
2020-04-30 18:24:43 +02:00
|
|
|
pub fn print_backtrace(&self) {
|
2021-02-14 00:00:00 +00:00
|
|
|
if let Some(backtrace) = self.0.backtrace.as_ref() {
|
2020-04-30 18:24:43 +02:00
|
|
|
print_backtrace(backtrace);
|
2018-09-18 11:01:13 +02:00
|
|
|
}
|
|
|
|
}
|
2021-02-14 00:00:00 +00:00
|
|
|
|
|
|
|
pub fn into_kind(self) -> InterpError<'tcx> {
|
|
|
|
let InterpErrorInfo(box InterpErrorInfoInner { kind, .. }) = self;
|
|
|
|
kind
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn kind(&self) -> &InterpError<'tcx> {
|
|
|
|
&self.0.kind
|
|
|
|
}
|
2018-09-18 11:01:13 +02:00
|
|
|
}
|
|
|
|
|
2020-04-30 18:24:43 +02:00
|
|
|
fn print_backtrace(backtrace: &Backtrace) {
|
|
|
|
eprintln!("\n\nAn error occurred in miri:\n{}", backtrace);
|
2017-08-02 16:59:01 +02:00
|
|
|
}
|
|
|
|
|
2020-03-05 23:31:39 +01:00
|
|
|
impl From<ErrorHandled> for InterpErrorInfo<'_> {
|
2019-06-07 19:22:42 +02:00
|
|
|
fn from(err: ErrorHandled) -> Self {
|
|
|
|
match err {
|
2022-01-22 18:49:12 -06:00
|
|
|
ErrorHandled::Reported(ErrorGuaranteed { .. }) | ErrorHandled::Linted => {
|
2020-04-12 04:24:25 +03:00
|
|
|
err_inval!(ReferencedConstant)
|
|
|
|
}
|
2019-06-07 19:22:42 +02:00
|
|
|
ErrorHandled::TooGeneric => err_inval!(TooGeneric),
|
|
|
|
}
|
|
|
|
.into()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-23 12:34:26 -06:00
|
|
|
impl From<ErrorGuaranteed> for InterpErrorInfo<'_> {
|
|
|
|
fn from(err: ErrorGuaranteed) -> Self {
|
2020-11-04 22:23:43 +05:30
|
|
|
InterpError::InvalidProgram(InvalidProgramInfo::AlreadyReported(err)).into()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-24 10:24:55 +02:00
|
|
|
impl<'tcx> From<InterpError<'tcx>> for InterpErrorInfo<'tcx> {
|
|
|
|
fn from(kind: InterpError<'tcx>) -> Self {
|
2020-07-31 16:38:32 +10:00
|
|
|
let capture_backtrace = tls::with_opt(|tcx| {
|
|
|
|
if let Some(tcx) = tcx {
|
|
|
|
*Lock::borrow(&tcx.sess.ctfe_backtrace)
|
2020-02-16 20:32:25 -05:00
|
|
|
} else {
|
|
|
|
CtfeBacktrace::Disabled
|
|
|
|
}
|
|
|
|
});
|
2018-06-03 03:01:06 +02:00
|
|
|
|
2020-02-16 20:32:25 -05:00
|
|
|
let backtrace = match capture_backtrace {
|
|
|
|
CtfeBacktrace::Disabled => None,
|
2020-04-30 18:24:43 +02:00
|
|
|
CtfeBacktrace::Capture => Some(Box::new(Backtrace::force_capture())),
|
2020-02-16 20:32:25 -05:00
|
|
|
CtfeBacktrace::Immediate => {
|
|
|
|
// Print it now.
|
2020-04-30 18:24:43 +02:00
|
|
|
let backtrace = Backtrace::force_capture();
|
|
|
|
print_backtrace(&backtrace);
|
2020-02-16 20:32:25 -05:00
|
|
|
None
|
2018-06-03 03:01:06 +02:00
|
|
|
}
|
2018-09-18 11:01:13 +02:00
|
|
|
};
|
2020-02-16 20:32:25 -05:00
|
|
|
|
2021-02-14 00:00:00 +00:00
|
|
|
InterpErrorInfo(Box::new(InterpErrorInfoInner { 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,
|
2020-11-04 22:23:43 +05:30
|
|
|
/// Abort in case errors are already reported.
|
2022-01-23 12:34:26 -06:00
|
|
|
AlreadyReported(ErrorGuaranteed),
|
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>),
|
2021-12-11 18:45:03 -05:00
|
|
|
/// An error occurred during FnAbi computation: the passed --target lacks FFI support
|
|
|
|
/// (which unfortunately typeck does not reject).
|
|
|
|
/// Not using `FnAbiError` as that contains a nested `LayoutError`.
|
|
|
|
FnAbiAdjustForForeignAbi(call::AdjustForForeignAbiError),
|
2021-01-21 20:10:40 +03:00
|
|
|
/// SizeOf of unsized type was requested.
|
|
|
|
SizeOfUnsizedType(Ty<'tcx>),
|
2019-07-25 16:59:38 +05:30
|
|
|
}
|
|
|
|
|
2020-04-30 11:03:55 +02:00
|
|
|
impl fmt::Display for InvalidProgramInfo<'_> {
|
2019-07-27 17:49:12 +05:30
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
use InvalidProgramInfo::*;
|
|
|
|
match self {
|
|
|
|
TooGeneric => write!(f, "encountered overly generic constant"),
|
|
|
|
ReferencedConstant => write!(f, "referenced constant has errors"),
|
2022-01-22 18:49:12 -06:00
|
|
|
AlreadyReported(ErrorGuaranteed { .. }) => {
|
2020-04-12 04:24:25 +03:00
|
|
|
write!(f, "encountered constants with type errors, stopping evaluation")
|
|
|
|
}
|
2019-07-31 16:22:34 -07:00
|
|
|
Layout(ref err) => write!(f, "{}", err),
|
2021-12-11 18:45:03 -05:00
|
|
|
FnAbiAdjustForForeignAbi(ref err) => write!(f, "{}", err),
|
2021-01-21 20:10:40 +03:00
|
|
|
SizeOfUnsizedType(ty) => write!(f, "size_of called on unsized type `{}`", ty),
|
2019-07-27 17:49:12 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-30 20:37:58 +02:00
|
|
|
/// Details of why a pointer had to be in-bounds.
|
2020-06-11 15:49:57 +01:00
|
|
|
#[derive(Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)]
|
2020-04-30 20:37:58 +02:00
|
|
|
pub enum CheckInAllocMsg {
|
2021-07-14 09:56:54 +02:00
|
|
|
/// We are dereferencing a pointer (i.e., creating a place).
|
|
|
|
DerefTest,
|
2021-05-07 15:11:18 +02:00
|
|
|
/// We are access memory.
|
2020-04-30 20:37:58 +02:00
|
|
|
MemoryAccessTest,
|
2021-05-07 15:11:18 +02:00
|
|
|
/// We are doing pointer arithmetic.
|
2020-04-30 20:37:58 +02:00
|
|
|
PointerArithmeticTest,
|
2022-03-10 18:30:32 -05:00
|
|
|
/// We are doing pointer offset_from.
|
|
|
|
OffsetFromTest,
|
2021-05-07 15:11:18 +02:00
|
|
|
/// None of the above -- generic/unspecific inbounds test.
|
2020-04-30 20:37:58 +02:00
|
|
|
InboundsTest,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for CheckInAllocMsg {
|
2021-07-15 20:07:01 +02:00
|
|
|
/// When this is printed as an error the context looks like this:
|
2022-07-03 15:46:22 -04:00
|
|
|
/// "{msg}{pointer} is a dangling pointer".
|
2020-04-30 20:37:58 +02:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
write!(
|
|
|
|
f,
|
|
|
|
"{}",
|
|
|
|
match *self {
|
2021-07-14 09:56:54 +02:00
|
|
|
CheckInAllocMsg::DerefTest => "dereferencing pointer failed: ",
|
2021-05-07 15:11:18 +02:00
|
|
|
CheckInAllocMsg::MemoryAccessTest => "memory access failed: ",
|
2022-07-03 15:46:22 -04:00
|
|
|
CheckInAllocMsg::PointerArithmeticTest => "out-of-bounds pointer arithmetic: ",
|
2022-03-10 18:30:32 -05:00
|
|
|
CheckInAllocMsg::OffsetFromTest => "out-of-bounds offset_from: ",
|
2022-07-03 15:46:22 -04:00
|
|
|
CheckInAllocMsg::InboundsTest => "out-of-bounds pointer use: ",
|
2020-04-30 20:37:58 +02:00
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-14 07:46:43 -05:00
|
|
|
/// Details of an access to uninitialized bytes where it is not allowed.
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct UninitBytesAccess {
|
|
|
|
/// Location of the original memory access.
|
2021-05-16 18:53:20 +02:00
|
|
|
pub access_offset: Size,
|
2020-05-14 07:46:43 -05:00
|
|
|
/// Size of the original memory access.
|
|
|
|
pub access_size: Size,
|
|
|
|
/// Location of the first uninitialized byte that was accessed.
|
2021-05-16 18:53:20 +02:00
|
|
|
pub uninit_offset: Size,
|
2020-05-14 07:46:43 -05:00
|
|
|
/// Number of consecutive uninitialized bytes that were accessed.
|
|
|
|
pub uninit_size: Size,
|
|
|
|
}
|
|
|
|
|
2022-04-07 16:22:09 -04:00
|
|
|
/// Information about a size mismatch.
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct ScalarSizeMismatch {
|
|
|
|
pub target_size: u64,
|
|
|
|
pub data_size: u64,
|
|
|
|
}
|
|
|
|
|
2019-09-17 08:58:51 +02:00
|
|
|
/// Error information for when the program caused Undefined Behavior.
|
2020-05-06 11:31:05 +02:00
|
|
|
pub enum UndefinedBehaviorInfo<'tcx> {
|
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-07-27 17:49:12 +05:30
|
|
|
/// Unreachable code was executed.
|
2019-07-26 15:28:27 +05:30
|
|
|
Unreachable,
|
2019-12-01 12:08:05 +01:00
|
|
|
/// A slice/array index projection went out-of-bounds.
|
2020-03-08 19:44:09 +01:00
|
|
|
BoundsCheckFailed {
|
|
|
|
len: u64,
|
|
|
|
index: u64,
|
|
|
|
},
|
2019-12-01 12:08:05 +01:00
|
|
|
/// Something was divided by 0 (x / 0).
|
|
|
|
DivisionByZero,
|
|
|
|
/// Something was "remainded" by 0 (x % 0).
|
|
|
|
RemainderByZero,
|
2022-03-01 20:02:59 -05:00
|
|
|
/// Signed division overflowed (INT_MIN / -1).
|
|
|
|
DivisionOverflow,
|
|
|
|
/// Signed remainder overflowed (INT_MIN % -1).
|
|
|
|
RemainderOverflow,
|
2019-12-01 12:08:05 +01:00
|
|
|
/// Overflowing inbounds pointer arithmetic.
|
|
|
|
PointerArithOverflow,
|
2020-03-05 23:31:39 +01:00
|
|
|
/// Invalid metadata in a wide pointer (using `str` to avoid allocations).
|
2020-03-06 18:14:41 +01:00
|
|
|
InvalidMeta(&'static str),
|
2020-05-06 11:31:05 +02:00
|
|
|
/// Invalid drop function in vtable.
|
2021-06-12 13:13:38 +02:00
|
|
|
InvalidVtableDropFn(FnSig<'tcx>),
|
|
|
|
/// Invalid size in a vtable: too large.
|
|
|
|
InvalidVtableSize,
|
|
|
|
/// Invalid alignment in a vtable: too large, or not a power of 2.
|
|
|
|
InvalidVtableAlignment(String),
|
2020-03-08 18:52:30 +01:00
|
|
|
/// Reading a C string that does not end within its allocation.
|
|
|
|
UnterminatedCString(Pointer),
|
|
|
|
/// Dereferencing a dangling pointer after it got freed.
|
|
|
|
PointerUseAfterFree(AllocId),
|
|
|
|
/// Used a pointer outside the bounds it is valid for.
|
2021-07-17 20:12:28 +02:00
|
|
|
/// (If `ptr_size > 0`, determines the size of the memory range that was expected to be in-bounds.)
|
2020-03-08 18:52:30 +01:00
|
|
|
PointerOutOfBounds {
|
2021-07-12 18:22:15 +02:00
|
|
|
alloc_id: AllocId,
|
2021-07-17 20:12:28 +02:00
|
|
|
alloc_size: Size,
|
|
|
|
ptr_offset: i64,
|
|
|
|
ptr_size: Size,
|
2020-03-08 18:52:30 +01:00
|
|
|
msg: CheckInAllocMsg,
|
|
|
|
},
|
2020-04-30 20:37:58 +02:00
|
|
|
/// Using an integer as a pointer in the wrong way.
|
|
|
|
DanglingIntPointer(u64, CheckInAllocMsg),
|
2020-03-08 18:52:30 +01:00
|
|
|
/// Used a pointer with bad alignment.
|
|
|
|
AlignmentCheckFailed {
|
|
|
|
required: Align,
|
|
|
|
has: Align,
|
|
|
|
},
|
|
|
|
/// Writing to read-only memory.
|
|
|
|
WriteToReadOnly(AllocId),
|
|
|
|
// Trying to access the data behind a function pointer.
|
|
|
|
DerefFunctionPointer(AllocId),
|
|
|
|
/// The value validity check found a problem.
|
|
|
|
/// Should only be thrown by `validity.rs` and always point out which part of the value
|
|
|
|
/// is the problem.
|
2021-06-13 22:40:42 +02:00
|
|
|
ValidationFailure {
|
2021-06-14 18:57:06 +02:00
|
|
|
/// The "path" to the value in question, e.g. `.0[5].field` for a struct
|
|
|
|
/// field in the 6th element of an array that is the first element of a tuple.
|
2021-06-13 22:40:42 +02:00
|
|
|
path: Option<String>,
|
|
|
|
msg: String,
|
|
|
|
},
|
2020-03-08 18:52:30 +01:00
|
|
|
/// Using a non-boolean `u8` as bool.
|
|
|
|
InvalidBool(u8),
|
|
|
|
/// Using a non-character `u32` as character.
|
|
|
|
InvalidChar(u32),
|
2020-05-30 14:21:56 +02:00
|
|
|
/// The tag of an enum does not encode an actual discriminant.
|
|
|
|
InvalidTag(Scalar),
|
2020-04-30 20:37:58 +02:00
|
|
|
/// Using a pointer-not-to-a-function as function pointer.
|
|
|
|
InvalidFunctionPointer(Pointer),
|
2020-05-06 00:07:53 +02:00
|
|
|
/// Using a string that is not valid UTF-8,
|
|
|
|
InvalidStr(std::str::Utf8Error),
|
2020-03-08 18:52:30 +01:00
|
|
|
/// Using uninitialized data where it is not allowed.
|
2021-05-16 18:53:20 +02:00
|
|
|
InvalidUninitBytes(Option<(AllocId, UninitBytesAccess)>),
|
2020-03-08 18:52:30 +01:00
|
|
|
/// Working with a local that is not currently live.
|
|
|
|
DeadLocal,
|
2020-04-26 18:44:38 +02:00
|
|
|
/// Data size is not equal to target size.
|
2022-04-07 16:22:09 -04:00
|
|
|
ScalarSizeMismatch(ScalarSizeMismatch),
|
2021-10-13 16:53:09 -04:00
|
|
|
/// A discriminant of an uninhabited enum variant is written.
|
|
|
|
UninhabitedEnumVariantWritten,
|
2019-07-26 10:51:54 +05:30
|
|
|
}
|
|
|
|
|
2020-05-06 11:31:05 +02:00
|
|
|
impl fmt::Display 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 {
|
2020-03-22 22:54:41 +01:00
|
|
|
Ub(msg) => write!(f, "{}", msg),
|
2019-12-01 12:08:05 +01:00
|
|
|
Unreachable => write!(f, "entering unreachable code"),
|
2020-04-30 11:03:55 +02:00
|
|
|
BoundsCheckFailed { ref len, ref index } => {
|
|
|
|
write!(f, "indexing out of bounds: the len is {} but the index is {}", len, index)
|
|
|
|
}
|
2019-12-01 12:08:05 +01:00
|
|
|
DivisionByZero => write!(f, "dividing by zero"),
|
|
|
|
RemainderByZero => write!(f, "calculating the remainder with a divisor of zero"),
|
2022-03-01 20:02:59 -05:00
|
|
|
DivisionOverflow => write!(f, "overflow in signed division (dividing MIN by -1)"),
|
|
|
|
RemainderOverflow => write!(f, "overflow in signed remainder (dividing MIN by -1)"),
|
2019-12-01 12:08:05 +01:00
|
|
|
PointerArithOverflow => write!(f, "overflowing in-bounds pointer arithmetic"),
|
2020-03-05 23:31:39 +01:00
|
|
|
InvalidMeta(msg) => write!(f, "invalid metadata in wide pointer: {}", msg),
|
2021-06-12 13:13:38 +02:00
|
|
|
InvalidVtableDropFn(sig) => write!(
|
2020-05-06 11:31:05 +02:00
|
|
|
f,
|
|
|
|
"invalid drop function signature: got {}, expected exactly one argument which must be a pointer type",
|
|
|
|
sig
|
|
|
|
),
|
2021-06-12 13:13:38 +02:00
|
|
|
InvalidVtableSize => {
|
|
|
|
write!(f, "invalid vtable: size is bigger than largest supported object")
|
|
|
|
}
|
|
|
|
InvalidVtableAlignment(msg) => write!(f, "invalid vtable: alignment {}", msg),
|
2020-03-08 18:52:30 +01:00
|
|
|
UnterminatedCString(p) => write!(
|
|
|
|
f,
|
2021-07-12 18:22:15 +02:00
|
|
|
"reading a null-terminated string starting at {:?} with no null found before end of allocation",
|
2020-03-08 18:52:30 +01:00
|
|
|
p,
|
|
|
|
),
|
2020-03-08 19:44:09 +01:00
|
|
|
PointerUseAfterFree(a) => {
|
2022-07-02 10:53:34 -04:00
|
|
|
write!(f, "pointer to {a:?} was dereferenced after this allocation got freed")
|
2020-03-08 19:44:09 +01:00
|
|
|
}
|
2021-07-17 20:12:28 +02:00
|
|
|
PointerOutOfBounds { alloc_id, alloc_size, ptr_offset, ptr_size: Size::ZERO, msg } => {
|
2021-07-15 20:07:01 +02:00
|
|
|
write!(
|
|
|
|
f,
|
2022-07-02 10:53:34 -04:00
|
|
|
"{msg}{alloc_id:?} has size {alloc_size}, so pointer at offset {ptr_offset} is out-of-bounds",
|
2021-07-17 20:12:28 +02:00
|
|
|
alloc_size = alloc_size.bytes(),
|
2021-07-15 20:07:01 +02:00
|
|
|
)
|
|
|
|
}
|
2021-07-17 20:12:28 +02:00
|
|
|
PointerOutOfBounds { alloc_id, alloc_size, ptr_offset, ptr_size, msg } => write!(
|
2020-03-08 18:52:30 +01:00
|
|
|
f,
|
2022-07-02 10:53:34 -04:00
|
|
|
"{msg}{alloc_id:?} has size {alloc_size}, so pointer to {ptr_size} byte{ptr_size_p} starting at offset {ptr_offset} is out-of-bounds",
|
2021-07-17 20:12:28 +02:00
|
|
|
alloc_size = alloc_size.bytes(),
|
|
|
|
ptr_size = ptr_size.bytes(),
|
|
|
|
ptr_size_p = pluralize!(ptr_size.bytes()),
|
2020-03-08 18:52:30 +01:00
|
|
|
),
|
2020-04-30 20:37:58 +02:00
|
|
|
DanglingIntPointer(i, msg) => {
|
2022-07-03 15:46:22 -04:00
|
|
|
write!(
|
|
|
|
f,
|
|
|
|
"{msg}{pointer} is a dangling pointer (it has no provenance)",
|
|
|
|
pointer = Pointer::<Option<AllocId>>::from_addr(*i),
|
|
|
|
)
|
2020-04-30 20:37:58 +02:00
|
|
|
}
|
2020-03-08 18:52:30 +01:00
|
|
|
AlignmentCheckFailed { required, has } => write!(
|
|
|
|
f,
|
|
|
|
"accessing memory with alignment {}, but alignment {} is required",
|
|
|
|
has.bytes(),
|
|
|
|
required.bytes()
|
|
|
|
),
|
2022-07-02 10:53:34 -04:00
|
|
|
WriteToReadOnly(a) => write!(f, "writing to {a:?} which is read-only"),
|
|
|
|
DerefFunctionPointer(a) => write!(f, "accessing {a:?} which contains a function"),
|
2022-06-25 23:46:51 -04:00
|
|
|
ValidationFailure { path: None, msg } => {
|
|
|
|
write!(f, "constructing invalid value: {}", msg)
|
|
|
|
}
|
2021-06-13 22:40:42 +02:00
|
|
|
ValidationFailure { path: Some(path), msg } => {
|
2022-06-25 23:46:51 -04:00
|
|
|
write!(f, "constructing invalid value at {}: {}", path, msg)
|
2021-06-13 22:40:42 +02:00
|
|
|
}
|
2020-05-01 10:56:17 +02:00
|
|
|
InvalidBool(b) => {
|
2020-05-01 14:39:41 +02:00
|
|
|
write!(f, "interpreting an invalid 8-bit value as a bool: 0x{:02x}", b)
|
2020-05-01 10:56:17 +02:00
|
|
|
}
|
|
|
|
InvalidChar(c) => {
|
2020-05-01 14:39:41 +02:00
|
|
|
write!(f, "interpreting an invalid 32-bit value as a char: 0x{:08x}", c)
|
2020-05-01 10:56:17 +02:00
|
|
|
}
|
2022-02-20 16:43:21 +01:00
|
|
|
InvalidTag(val) => write!(f, "enum value has invalid tag: {:x}", val),
|
2020-04-30 20:37:58 +02:00
|
|
|
InvalidFunctionPointer(p) => {
|
2021-07-12 18:22:15 +02:00
|
|
|
write!(f, "using {:?} as function pointer but it does not point to a function", p)
|
2020-04-30 20:37:58 +02:00
|
|
|
}
|
2020-05-06 11:31:05 +02:00
|
|
|
InvalidStr(err) => write!(f, "this string is not valid UTF-8: {}", err),
|
2021-05-16 18:53:20 +02:00
|
|
|
InvalidUninitBytes(Some((alloc, access))) => write!(
|
2020-03-08 19:44:09 +01:00
|
|
|
f,
|
2021-07-12 18:22:15 +02:00
|
|
|
"reading {} byte{} of memory starting at {:?}, \
|
|
|
|
but {} byte{} {} uninitialized starting at {:?}, \
|
2020-05-14 07:46:43 -05:00
|
|
|
and this operation requires initialized memory",
|
|
|
|
access.access_size.bytes(),
|
|
|
|
pluralize!(access.access_size.bytes()),
|
2021-05-16 18:53:20 +02:00
|
|
|
Pointer::new(*alloc, access.access_offset),
|
2020-05-14 07:46:43 -05:00
|
|
|
access.uninit_size.bytes(),
|
|
|
|
pluralize!(access.uninit_size.bytes()),
|
2022-03-14 17:55:14 +01:00
|
|
|
pluralize!("is", access.uninit_size.bytes()),
|
2021-05-16 18:53:20 +02:00
|
|
|
Pointer::new(*alloc, access.uninit_offset),
|
2020-03-08 19:44:09 +01:00
|
|
|
),
|
2020-04-22 03:20:40 -04:00
|
|
|
InvalidUninitBytes(None) => write!(
|
2020-03-08 19:44:09 +01:00
|
|
|
f,
|
|
|
|
"using uninitialized data, but this operation requires initialized memory"
|
|
|
|
),
|
2020-03-08 18:52:30 +01:00
|
|
|
DeadLocal => write!(f, "accessing a dead local variable"),
|
2022-04-07 16:22:09 -04:00
|
|
|
ScalarSizeMismatch(self::ScalarSizeMismatch { target_size, data_size }) => write!(
|
2020-04-26 08:58:22 +05:30
|
|
|
f,
|
2020-04-26 20:11:14 +05:30
|
|
|
"scalar size mismatch: expected {} bytes but got {} bytes instead",
|
2020-04-26 08:58:22 +05:30
|
|
|
target_size, data_size
|
|
|
|
),
|
2021-10-13 16:53:09 -04:00
|
|
|
UninhabitedEnumVariantWritten => {
|
|
|
|
write!(f, "writing discriminant of an uninhabited enum")
|
|
|
|
}
|
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
|
2020-04-30 14:53:28 +02:00
|
|
|
/// Miri engine, e.g., CTFE does not support dereferencing pointers at integral addresses.
|
2020-03-08 18:52:30 +01:00
|
|
|
pub enum UnsupportedOpInfo {
|
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),
|
2020-03-08 18:52:30 +01:00
|
|
|
/// Encountered a pointer where we needed raw bytes.
|
2019-07-26 15:28:27 +05:30
|
|
|
ReadPointerAsBytes,
|
2021-07-30 22:34:35 +02:00
|
|
|
/// Overwriting parts of a pointer; the resulting state cannot be represented in our
|
2022-06-02 20:30:29 -04:00
|
|
|
/// `Allocation` data structure. See <https://github.com/rust-lang/miri/issues/2181>.
|
2021-07-18 11:15:17 +02:00
|
|
|
PartialPointerOverwrite(Pointer<AllocId>),
|
2020-04-30 17:05:36 +02:00
|
|
|
//
|
2020-04-16 17:32:48 +02:00
|
|
|
// The variants below are only reachable from CTFE/const prop, miri will never emit them.
|
2020-04-30 17:05:36 +02:00
|
|
|
//
|
2020-05-02 21:44:25 +02:00
|
|
|
/// Accessing thread local statics
|
|
|
|
ThreadLocalStatic(DefId),
|
2020-07-26 11:11:17 +02:00
|
|
|
/// Accessing an unsupported extern static.
|
|
|
|
ReadExternStatic(DefId),
|
2016-03-14 21:48:00 -06:00
|
|
|
}
|
|
|
|
|
2020-04-30 11:03:55 +02:00
|
|
|
impl fmt::Display for UnsupportedOpInfo {
|
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 {
|
2020-03-08 18:52:30 +01:00
|
|
|
Unsupported(ref msg) => write!(f, "{}", msg),
|
2021-07-18 11:15:17 +02:00
|
|
|
ReadPointerAsBytes => write!(f, "unable to turn pointer into raw bytes"),
|
|
|
|
PartialPointerOverwrite(ptr) => {
|
|
|
|
write!(f, "unable to overwrite parts of a pointer in memory at {:?}", ptr)
|
|
|
|
}
|
2020-06-01 20:53:45 +02:00
|
|
|
ThreadLocalStatic(did) => write!(f, "cannot access thread local static ({:?})", did),
|
2021-07-18 11:15:17 +02:00
|
|
|
ReadExternStatic(did) => write!(f, "cannot read from extern static ({:?})", did),
|
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,
|
2020-03-17 16:07:29 -07:00
|
|
|
/// The program ran for too long.
|
|
|
|
///
|
|
|
|
/// The exact limit is set by the `const_eval_limit` attribute.
|
2020-03-22 12:49:58 -07:00
|
|
|
StepLimitReached,
|
2021-06-12 19:49:48 -04:00
|
|
|
/// There is not enough memory to perform an allocation.
|
|
|
|
MemoryExhausted,
|
2019-07-28 20:07:33 +05:30
|
|
|
}
|
|
|
|
|
2020-04-30 11:03:55 +02:00
|
|
|
impl fmt::Display for ResourceExhaustionInfo {
|
2019-07-28 20:07:33 +05:30
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
use ResourceExhaustionInfo::*;
|
|
|
|
match self {
|
|
|
|
StackFrameLimitReached => {
|
|
|
|
write!(f, "reached the configured maximum number of stack frames")
|
2019-12-22 17:42:04 -05:00
|
|
|
}
|
2020-03-22 12:49:58 -07:00
|
|
|
StepLimitReached => {
|
|
|
|
write!(f, "exceeded interpreter step limit (see `#[const_eval_limit]`)")
|
|
|
|
}
|
2021-06-12 19:49:48 -04:00
|
|
|
MemoryExhausted => {
|
|
|
|
write!(f, "tried to allocate more memory than available to compiler")
|
|
|
|
}
|
2019-07-28 20:07:33 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-22 20:24:22 +01:00
|
|
|
/// A trait to work around not having trait object upcasting.
|
|
|
|
pub trait AsAny: Any {
|
|
|
|
fn as_any(&self) -> &dyn Any;
|
|
|
|
}
|
|
|
|
impl<T: Any> AsAny for T {
|
|
|
|
#[inline(always)]
|
|
|
|
fn as_any(&self) -> &dyn Any {
|
|
|
|
self
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-22 11:41:07 +01:00
|
|
|
/// A trait for machine-specific errors (or other "machine stop" conditions).
|
2021-05-25 20:54:59 -05:00
|
|
|
pub trait MachineStopType: AsAny + fmt::Display + Send {
|
|
|
|
/// If `true`, emit a hard error instead of going through the `CONST_ERR` lint
|
|
|
|
fn is_hard_err(&self) -> bool {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
}
|
2020-03-22 11:41:07 +01:00
|
|
|
|
|
|
|
impl dyn MachineStopType {
|
2020-03-22 20:24:22 +01:00
|
|
|
#[inline(always)]
|
2020-03-22 11:41:07 +01:00
|
|
|
pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
|
2020-03-22 20:24:22 +01:00
|
|
|
self.as_any().downcast_ref()
|
2020-03-22 11:41:07 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-28 20:07:33 +05:30
|
|
|
pub enum InterpError<'tcx> {
|
|
|
|
/// The program caused undefined behavior.
|
2020-05-06 11:31:05 +02:00
|
|
|
UndefinedBehavior(UndefinedBehaviorInfo<'tcx>),
|
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).
|
2020-03-08 18:52:30 +01:00
|
|
|
Unsupported(UnsupportedOpInfo),
|
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.
|
2020-03-22 11:41:07 +01:00
|
|
|
MachineStop(Box<dyn MachineStopType>),
|
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 {
|
2020-04-30 11:03:55 +02:00
|
|
|
use InterpError::*;
|
|
|
|
match *self {
|
|
|
|
Unsupported(ref msg) => write!(f, "{}", msg),
|
|
|
|
InvalidProgram(ref msg) => write!(f, "{}", msg),
|
|
|
|
UndefinedBehavior(ref msg) => write!(f, "{}", msg),
|
|
|
|
ResourceExhaustion(ref msg) => write!(f, "{}", msg),
|
|
|
|
MachineStop(ref msg) => write!(f, "{}", msg),
|
|
|
|
}
|
2019-07-28 20:07:33 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-30 11:03:55 +02:00
|
|
|
// Forward `Debug` to `Display`, so it does not look awful.
|
2019-07-28 20:07:33 +05:30
|
|
|
impl fmt::Debug for InterpError<'_> {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
2020-04-30 11:03:55 +02:00
|
|
|
fmt::Display::fmt(self, f)
|
2018-04-26 11:37:03 +02:00
|
|
|
}
|
|
|
|
}
|
2020-03-04 08:40:13 +01:00
|
|
|
|
|
|
|
impl InterpError<'_> {
|
2021-06-13 22:40:42 +02:00
|
|
|
/// Some errors do string formatting even if the error is never printed.
|
2021-02-20 19:01:25 +01:00
|
|
|
/// To avoid performance issues, there are places where we want to be sure to never raise these formatting errors,
|
|
|
|
/// so this method lets us detect them and `bug!` on unexpected errors.
|
|
|
|
pub fn formatted_string(&self) -> bool {
|
2021-11-06 01:31:32 +01:00
|
|
|
matches!(
|
|
|
|
self,
|
2020-03-22 11:41:07 +01:00
|
|
|
InterpError::Unsupported(UnsupportedOpInfo::Unsupported(_))
|
2021-11-06 01:31:32 +01:00
|
|
|
| InterpError::UndefinedBehavior(UndefinedBehaviorInfo::ValidationFailure { .. })
|
|
|
|
| InterpError::UndefinedBehavior(UndefinedBehaviorInfo::Ub(_))
|
|
|
|
)
|
2020-03-04 08:40:13 +01:00
|
|
|
}
|
2021-06-16 18:23:34 -04:00
|
|
|
|
|
|
|
/// Should this error be reported as a hard error, preventing compilation, or a soft error,
|
|
|
|
/// causing a deny-by-default lint?
|
|
|
|
pub fn is_hard_err(&self) -> bool {
|
|
|
|
use InterpError::*;
|
|
|
|
match *self {
|
|
|
|
MachineStop(ref err) => err.is_hard_err(),
|
2021-06-15 18:24:39 -04:00
|
|
|
UndefinedBehavior(_) => true,
|
|
|
|
ResourceExhaustion(ResourceExhaustionInfo::MemoryExhausted) => true,
|
2021-06-16 18:23:34 -04:00
|
|
|
_ => false,
|
|
|
|
}
|
|
|
|
}
|
2020-03-04 08:40:13 +01:00
|
|
|
}
|