1 use super::{AllocId, ConstAlloc, Pointer, Scalar}
;
3 use crate::mir
::interpret
::ConstValue
;
4 use crate::ty
::{layout, query::TyCtxtAt, tls, FnSig, Ty}
;
6 use rustc_data_structures
::sync
::Lock
;
7 use rustc_errors
::{pluralize, struct_span_err, DiagnosticBuilder, ErrorReported}
;
8 use rustc_macros
::HashStable
;
9 use rustc_session
::CtfeBacktrace
;
10 use rustc_span
::def_id
::DefId
;
11 use rustc_target
::abi
::{Align, Size}
;
12 use std
::{any::Any, backtrace::Backtrace, fmt, mem}
;
14 #[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
15 pub enum ErrorHandled
{
16 /// Already reported an error for this evaluation, and the compilation is
17 /// *guaranteed* to fail. Warnings/lints *must not* produce `Reported`.
18 Reported(ErrorReported
),
19 /// Already emitted a lint for this evaluation.
21 /// Don't emit an error, the evaluation failed because the MIR was generic
22 /// and the substs didn't fully monomorphize it.
26 impl From
<ErrorReported
> for ErrorHandled
{
27 fn from(err
: ErrorReported
) -> ErrorHandled
{
28 ErrorHandled
::Reported(err
)
32 TrivialTypeFoldableAndLiftImpls
! {
36 pub type EvalToAllocationRawResult
<'tcx
> = Result
<ConstAlloc
<'tcx
>, ErrorHandled
>;
37 pub type EvalToConstValueResult
<'tcx
> = Result
<ConstValue
<'tcx
>, ErrorHandled
>;
39 pub fn struct_error
<'tcx
>(tcx
: TyCtxtAt
<'tcx
>, msg
: &str) -> DiagnosticBuilder
<'tcx
> {
40 struct_span_err
!(tcx
.sess
, tcx
.span
, E0080
, "{}", msg
)
43 /// Packages the kind of error we got from the const code interpreter
44 /// up with a Rust-level backtrace of where the error occurred.
45 /// Thsese should always be constructed by calling `.into()` on
46 /// a `InterpError`. In `librustc_mir::interpret`, we have `throw_err_*`
49 pub struct InterpErrorInfo
<'tcx
> {
50 pub kind
: InterpError
<'tcx
>,
51 backtrace
: Option
<Box
<Backtrace
>>,
54 impl fmt
::Display
for InterpErrorInfo
<'_
> {
55 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
56 write
!(f
, "{}", self.kind
)
60 impl InterpErrorInfo
<'_
> {
61 pub fn print_backtrace(&self) {
62 if let Some(backtrace
) = self.backtrace
.as_ref() {
63 print_backtrace(backtrace
);
68 fn print_backtrace(backtrace
: &Backtrace
) {
69 eprintln
!("\n\nAn error occurred in miri:\n{}", backtrace
);
72 impl From
<ErrorHandled
> for InterpErrorInfo
<'_
> {
73 fn from(err
: ErrorHandled
) -> Self {
75 ErrorHandled
::Reported(ErrorReported
) | ErrorHandled
::Linted
=> {
76 err_inval
!(ReferencedConstant
)
78 ErrorHandled
::TooGeneric
=> err_inval
!(TooGeneric
),
84 impl From
<ErrorReported
> for InterpErrorInfo
<'_
> {
85 fn from(err
: ErrorReported
) -> Self {
86 InterpError
::InvalidProgram(InvalidProgramInfo
::AlreadyReported(err
)).into()
90 impl<'tcx
> From
<InterpError
<'tcx
>> for InterpErrorInfo
<'tcx
> {
91 fn from(kind
: InterpError
<'tcx
>) -> Self {
92 let capture_backtrace
= tls
::with_opt(|tcx
| {
93 if let Some(tcx
) = tcx
{
94 *Lock
::borrow(&tcx
.sess
.ctfe_backtrace
)
96 CtfeBacktrace
::Disabled
100 let backtrace
= match capture_backtrace
{
101 CtfeBacktrace
::Disabled
=> None
,
102 CtfeBacktrace
::Capture
=> Some(Box
::new(Backtrace
::force_capture())),
103 CtfeBacktrace
::Immediate
=> {
105 let backtrace
= Backtrace
::force_capture();
106 print_backtrace(&backtrace
);
111 InterpErrorInfo { kind, backtrace }
115 /// Error information for when the program we executed turned out not to actually be a valid
116 /// program. This cannot happen in stand-alone Miri, but it can happen during CTFE/ConstProp
117 /// where we work on generic code or execution does not have all information available.
118 pub enum InvalidProgramInfo
<'tcx
> {
119 /// Resolution can fail if we are in a too generic context.
121 /// Cannot compute this constant because it depends on another one
122 /// which already produced an error.
124 /// Abort in case errors are already reported.
125 AlreadyReported(ErrorReported
),
126 /// An error occurred during layout computation.
127 Layout(layout
::LayoutError
<'tcx
>),
128 /// An invalid transmute happened.
129 TransmuteSizeDiff(Ty
<'tcx
>, Ty
<'tcx
>),
130 /// SizeOf of unsized type was requested.
131 SizeOfUnsizedType(Ty
<'tcx
>),
134 impl fmt
::Display
for InvalidProgramInfo
<'_
> {
135 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
136 use InvalidProgramInfo
::*;
138 TooGeneric
=> write
!(f
, "encountered overly generic constant"),
139 ReferencedConstant
=> write
!(f
, "referenced constant has errors"),
140 AlreadyReported(ErrorReported
) => {
141 write
!(f
, "encountered constants with type errors, stopping evaluation")
143 Layout(ref err
) => write
!(f
, "{}", err
),
144 TransmuteSizeDiff(from_ty
, to_ty
) => write
!(
146 "transmuting `{}` to `{}` is not possible, because these types do not have the same size",
149 SizeOfUnsizedType(ty
) => write
!(f
, "size_of called on unsized type `{}`", ty
),
154 /// Details of why a pointer had to be in-bounds.
155 #[derive(Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)]
156 pub enum CheckInAllocMsg
{
159 PointerArithmeticTest
,
163 impl fmt
::Display
for CheckInAllocMsg
{
164 /// When this is printed as an error the context looks like this
165 /// "{test name} failed: pointer must be in-bounds at offset..."
166 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
171 CheckInAllocMsg
::MemoryAccessTest
=> "memory access",
172 CheckInAllocMsg
::NullPointerTest
=> "NULL pointer test",
173 CheckInAllocMsg
::PointerArithmeticTest
=> "pointer arithmetic",
174 CheckInAllocMsg
::InboundsTest
=> "inbounds test",
180 /// Details of an access to uninitialized bytes where it is not allowed.
182 pub struct UninitBytesAccess
{
183 /// Location of the original memory access.
184 pub access_ptr
: Pointer
,
185 /// Size of the original memory access.
186 pub access_size
: Size
,
187 /// Location of the first uninitialized byte that was accessed.
188 pub uninit_ptr
: Pointer
,
189 /// Number of consecutive uninitialized bytes that were accessed.
190 pub uninit_size
: Size
,
193 /// Error information for when the program caused Undefined Behavior.
194 pub enum UndefinedBehaviorInfo
<'tcx
> {
195 /// Free-form case. Only for errors that are never caught!
197 /// Unreachable code was executed.
199 /// A slice/array index projection went out-of-bounds.
204 /// Something was divided by 0 (x / 0).
206 /// Something was "remainded" by 0 (x % 0).
208 /// Overflowing inbounds pointer arithmetic.
209 PointerArithOverflow
,
210 /// Invalid metadata in a wide pointer (using `str` to avoid allocations).
211 InvalidMeta(&'
static str),
212 /// Invalid drop function in vtable.
213 InvalidDropFn(FnSig
<'tcx
>),
214 /// Reading a C string that does not end within its allocation.
215 UnterminatedCString(Pointer
),
216 /// Dereferencing a dangling pointer after it got freed.
217 PointerUseAfterFree(AllocId
),
218 /// Used a pointer outside the bounds it is valid for.
221 msg
: CheckInAllocMsg
,
222 allocation_size
: Size
,
224 /// Using an integer as a pointer in the wrong way.
225 DanglingIntPointer(u64, CheckInAllocMsg
),
226 /// Used a pointer with bad alignment.
227 AlignmentCheckFailed
{
231 /// Writing to read-only memory.
232 WriteToReadOnly(AllocId
),
233 // Trying to access the data behind a function pointer.
234 DerefFunctionPointer(AllocId
),
235 /// The value validity check found a problem.
236 /// Should only be thrown by `validity.rs` and always point out which part of the value
238 ValidationFailure(String
),
239 /// Using a non-boolean `u8` as bool.
241 /// Using a non-character `u32` as character.
243 /// The tag of an enum does not encode an actual discriminant.
245 /// Using a pointer-not-to-a-function as function pointer.
246 InvalidFunctionPointer(Pointer
),
247 /// Using a string that is not valid UTF-8,
248 InvalidStr(std
::str::Utf8Error
),
249 /// Using uninitialized data where it is not allowed.
250 InvalidUninitBytes(Option
<Box
<UninitBytesAccess
>>),
251 /// Working with a local that is not currently live.
253 /// Data size is not equal to target size.
260 impl fmt
::Display
for UndefinedBehaviorInfo
<'_
> {
261 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
262 use UndefinedBehaviorInfo
::*;
264 Ub(msg
) => write
!(f
, "{}", msg
),
265 Unreachable
=> write
!(f
, "entering unreachable code"),
266 BoundsCheckFailed { ref len, ref index }
=> {
267 write
!(f
, "indexing out of bounds: the len is {} but the index is {}", len
, index
)
269 DivisionByZero
=> write
!(f
, "dividing by zero"),
270 RemainderByZero
=> write
!(f
, "calculating the remainder with a divisor of zero"),
271 PointerArithOverflow
=> write
!(f
, "overflowing in-bounds pointer arithmetic"),
272 InvalidMeta(msg
) => write
!(f
, "invalid metadata in wide pointer: {}", msg
),
273 InvalidDropFn(sig
) => write
!(
275 "invalid drop function signature: got {}, expected exactly one argument which must be a pointer type",
278 UnterminatedCString(p
) => write
!(
280 "reading a null-terminated string starting at {} with no null found before end of allocation",
283 PointerUseAfterFree(a
) => {
284 write
!(f
, "pointer to {} was dereferenced after this allocation got freed", a
)
286 PointerOutOfBounds { ptr, msg, allocation_size }
=> write
!(
288 "{} failed: pointer must be in-bounds at offset {}, \
289 but is outside bounds of {} which has size {}",
293 allocation_size
.bytes()
295 DanglingIntPointer(_
, CheckInAllocMsg
::NullPointerTest
) => {
296 write
!(f
, "NULL pointer is not allowed for this operation")
298 DanglingIntPointer(i
, msg
) => {
299 write
!(f
, "{} failed: 0x{:x} is not a valid pointer", msg
, i
)
301 AlignmentCheckFailed { required, has }
=> write
!(
303 "accessing memory with alignment {}, but alignment {} is required",
307 WriteToReadOnly(a
) => write
!(f
, "writing to {} which is read-only", a
),
308 DerefFunctionPointer(a
) => write
!(f
, "accessing {} which contains a function", a
),
309 ValidationFailure(ref err
) => write
!(f
, "type validation failed: {}", err
),
311 write
!(f
, "interpreting an invalid 8-bit value as a bool: 0x{:02x}", b
)
314 write
!(f
, "interpreting an invalid 32-bit value as a char: 0x{:08x}", c
)
316 InvalidTag(val
) => write
!(f
, "enum value has invalid tag: {}", val
),
317 InvalidFunctionPointer(p
) => {
318 write
!(f
, "using {} as function pointer but it does not point to a function", p
)
320 InvalidStr(err
) => write
!(f
, "this string is not valid UTF-8: {}", err
),
321 InvalidUninitBytes(Some(access
)) => write
!(
323 "reading {} byte{} of memory starting at {}, \
324 but {} byte{} {} uninitialized starting at {}, \
325 and this operation requires initialized memory",
326 access
.access_size
.bytes(),
327 pluralize
!(access
.access_size
.bytes()),
329 access
.uninit_size
.bytes(),
330 pluralize
!(access
.uninit_size
.bytes()),
331 if access
.uninit_size
.bytes() != 1 { "are" }
else { "is" }
,
334 InvalidUninitBytes(None
) => write
!(
336 "using uninitialized data, but this operation requires initialized memory"
338 DeadLocal
=> write
!(f
, "accessing a dead local variable"),
339 ScalarSizeMismatch { target_size, data_size }
=> write
!(
341 "scalar size mismatch: expected {} bytes but got {} bytes instead",
342 target_size
, data_size
348 /// Error information for when the program did something that might (or might not) be correct
349 /// to do according to the Rust spec, but due to limitations in the interpreter, the
350 /// operation could not be carried out. These limitations can differ between CTFE and the
351 /// Miri engine, e.g., CTFE does not support dereferencing pointers at integral addresses.
352 pub enum UnsupportedOpInfo
{
353 /// Free-form case. Only for errors that are never caught!
355 /// Could not find MIR for a function.
357 /// Encountered a pointer where we needed raw bytes.
360 // The variants below are only reachable from CTFE/const prop, miri will never emit them.
362 /// Encountered raw bytes where we needed a pointer.
364 /// Accessing thread local statics
365 ThreadLocalStatic(DefId
),
366 /// Accessing an unsupported extern static.
367 ReadExternStatic(DefId
),
370 impl fmt
::Display
for UnsupportedOpInfo
{
371 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
372 use UnsupportedOpInfo
::*;
374 Unsupported(ref msg
) => write
!(f
, "{}", msg
),
375 ReadExternStatic(did
) => write
!(f
, "cannot read from extern static ({:?})", did
),
376 NoMirFor(did
) => write
!(f
, "no MIR body is available for {:?}", did
),
377 ReadPointerAsBytes
=> write
!(f
, "unable to turn pointer into raw bytes",),
378 ReadBytesAsPointer
=> write
!(f
, "unable to turn bytes into a pointer"),
379 ThreadLocalStatic(did
) => write
!(f
, "cannot access thread local static ({:?})", did
),
384 /// Error information for when the program exhausted the resources granted to it
385 /// by the interpreter.
386 pub enum ResourceExhaustionInfo
{
387 /// The stack grew too big.
388 StackFrameLimitReached
,
389 /// The program ran for too long.
391 /// The exact limit is set by the `const_eval_limit` attribute.
395 impl fmt
::Display
for ResourceExhaustionInfo
{
396 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
397 use ResourceExhaustionInfo
::*;
399 StackFrameLimitReached
=> {
400 write
!(f
, "reached the configured maximum number of stack frames")
402 StepLimitReached
=> {
403 write
!(f
, "exceeded interpreter step limit (see `#[const_eval_limit]`)")
409 /// A trait to work around not having trait object upcasting.
410 pub trait AsAny
: Any
{
411 fn as_any(&self) -> &dyn Any
;
413 impl<T
: Any
> AsAny
for T
{
415 fn as_any(&self) -> &dyn Any
{
420 /// A trait for machine-specific errors (or other "machine stop" conditions).
421 pub trait MachineStopType
: AsAny
+ fmt
::Display
+ Send {}
422 impl MachineStopType
for String {}
424 impl dyn MachineStopType
{
426 pub fn downcast_ref
<T
: Any
>(&self) -> Option
<&T
> {
427 self.as_any().downcast_ref()
431 #[cfg(target_arch = "x86_64")]
432 static_assert_size
!(InterpError
<'_
>, 40);
434 pub enum InterpError
<'tcx
> {
435 /// The program caused undefined behavior.
436 UndefinedBehavior(UndefinedBehaviorInfo
<'tcx
>),
437 /// The program did something the interpreter does not support (some of these *might* be UB
438 /// but the interpreter is not sure).
439 Unsupported(UnsupportedOpInfo
),
440 /// The program was invalid (ill-typed, bad MIR, not sufficiently monomorphized, ...).
441 InvalidProgram(InvalidProgramInfo
<'tcx
>),
442 /// The program exhausted the interpreter's resources (stack/heap too big,
443 /// execution takes too long, ...).
444 ResourceExhaustion(ResourceExhaustionInfo
),
445 /// Stop execution for a machine-controlled reason. This is never raised by
446 /// the core engine itself.
447 MachineStop(Box
<dyn MachineStopType
>),
450 pub type InterpResult
<'tcx
, T
= ()> = Result
<T
, InterpErrorInfo
<'tcx
>>;
452 impl fmt
::Display
for InterpError
<'_
> {
453 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
456 Unsupported(ref msg
) => write
!(f
, "{}", msg
),
457 InvalidProgram(ref msg
) => write
!(f
, "{}", msg
),
458 UndefinedBehavior(ref msg
) => write
!(f
, "{}", msg
),
459 ResourceExhaustion(ref msg
) => write
!(f
, "{}", msg
),
460 MachineStop(ref msg
) => write
!(f
, "{}", msg
),
465 // Forward `Debug` to `Display`, so it does not look awful.
466 impl fmt
::Debug
for InterpError
<'_
> {
467 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
468 fmt
::Display
::fmt(self, f
)
472 impl InterpError
<'_
> {
473 /// Some errors allocate to be created as they contain free-form strings.
474 /// And sometimes we want to be sure that did not happen as it is a
475 /// waste of resources.
476 pub fn allocates(&self) -> bool
{
478 // Zero-sized boxes do not allocate.
479 InterpError
::MachineStop(b
) => mem
::size_of_val
::<dyn MachineStopType
>(&**b
) > 0,
480 InterpError
::Unsupported(UnsupportedOpInfo
::Unsupported(_
))
481 | InterpError
::UndefinedBehavior(UndefinedBehaviorInfo
::ValidationFailure(_
))
482 | InterpError
::UndefinedBehavior(UndefinedBehaviorInfo
::Ub(_
))
483 | InterpError
::UndefinedBehavior(UndefinedBehaviorInfo
::InvalidUninitBytes(Some(_
))) => {