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 CloneTypeFoldableAndLiftImpls
! {
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
>),
132 impl fmt
::Display
for InvalidProgramInfo
<'_
> {
133 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
134 use InvalidProgramInfo
::*;
136 TooGeneric
=> write
!(f
, "encountered overly generic constant"),
137 ReferencedConstant
=> write
!(f
, "referenced constant has errors"),
138 AlreadyReported(ErrorReported
) => {
139 write
!(f
, "encountered constants with type errors, stopping evaluation")
141 Layout(ref err
) => write
!(f
, "{}", err
),
142 TransmuteSizeDiff(from_ty
, to_ty
) => write
!(
144 "transmuting `{}` to `{}` is not possible, because these types do not have the same size",
151 /// Details of why a pointer had to be in-bounds.
152 #[derive(Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)]
153 pub enum CheckInAllocMsg
{
156 PointerArithmeticTest
,
160 impl fmt
::Display
for CheckInAllocMsg
{
161 /// When this is printed as an error the context looks like this
162 /// "{test name} failed: pointer must be in-bounds at offset..."
163 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
168 CheckInAllocMsg
::MemoryAccessTest
=> "memory access",
169 CheckInAllocMsg
::NullPointerTest
=> "NULL pointer test",
170 CheckInAllocMsg
::PointerArithmeticTest
=> "pointer arithmetic",
171 CheckInAllocMsg
::InboundsTest
=> "inbounds test",
177 /// Details of an access to uninitialized bytes where it is not allowed.
179 pub struct UninitBytesAccess
{
180 /// Location of the original memory access.
181 pub access_ptr
: Pointer
,
182 /// Size of the original memory access.
183 pub access_size
: Size
,
184 /// Location of the first uninitialized byte that was accessed.
185 pub uninit_ptr
: Pointer
,
186 /// Number of consecutive uninitialized bytes that were accessed.
187 pub uninit_size
: Size
,
190 /// Error information for when the program caused Undefined Behavior.
191 pub enum UndefinedBehaviorInfo
<'tcx
> {
192 /// Free-form case. Only for errors that are never caught!
194 /// Unreachable code was executed.
196 /// A slice/array index projection went out-of-bounds.
201 /// Something was divided by 0 (x / 0).
203 /// Something was "remainded" by 0 (x % 0).
205 /// Overflowing inbounds pointer arithmetic.
206 PointerArithOverflow
,
207 /// Invalid metadata in a wide pointer (using `str` to avoid allocations).
208 InvalidMeta(&'
static str),
209 /// Invalid drop function in vtable.
210 InvalidDropFn(FnSig
<'tcx
>),
211 /// Reading a C string that does not end within its allocation.
212 UnterminatedCString(Pointer
),
213 /// Dereferencing a dangling pointer after it got freed.
214 PointerUseAfterFree(AllocId
),
215 /// Used a pointer outside the bounds it is valid for.
218 msg
: CheckInAllocMsg
,
219 allocation_size
: Size
,
221 /// Using an integer as a pointer in the wrong way.
222 DanglingIntPointer(u64, CheckInAllocMsg
),
223 /// Used a pointer with bad alignment.
224 AlignmentCheckFailed
{
228 /// Writing to read-only memory.
229 WriteToReadOnly(AllocId
),
230 // Trying to access the data behind a function pointer.
231 DerefFunctionPointer(AllocId
),
232 /// The value validity check found a problem.
233 /// Should only be thrown by `validity.rs` and always point out which part of the value
235 ValidationFailure(String
),
236 /// Using a non-boolean `u8` as bool.
238 /// Using a non-character `u32` as character.
240 /// The tag of an enum does not encode an actual discriminant.
242 /// Using a pointer-not-to-a-function as function pointer.
243 InvalidFunctionPointer(Pointer
),
244 /// Using a string that is not valid UTF-8,
245 InvalidStr(std
::str::Utf8Error
),
246 /// Using uninitialized data where it is not allowed.
247 InvalidUninitBytes(Option
<Box
<UninitBytesAccess
>>),
248 /// Working with a local that is not currently live.
250 /// Data size is not equal to target size.
257 impl fmt
::Display
for UndefinedBehaviorInfo
<'_
> {
258 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
259 use UndefinedBehaviorInfo
::*;
261 Ub(msg
) => write
!(f
, "{}", msg
),
262 Unreachable
=> write
!(f
, "entering unreachable code"),
263 BoundsCheckFailed { ref len, ref index }
=> {
264 write
!(f
, "indexing out of bounds: the len is {} but the index is {}", len
, index
)
266 DivisionByZero
=> write
!(f
, "dividing by zero"),
267 RemainderByZero
=> write
!(f
, "calculating the remainder with a divisor of zero"),
268 PointerArithOverflow
=> write
!(f
, "overflowing in-bounds pointer arithmetic"),
269 InvalidMeta(msg
) => write
!(f
, "invalid metadata in wide pointer: {}", msg
),
270 InvalidDropFn(sig
) => write
!(
272 "invalid drop function signature: got {}, expected exactly one argument which must be a pointer type",
275 UnterminatedCString(p
) => write
!(
277 "reading a null-terminated string starting at {} with no null found before end of allocation",
280 PointerUseAfterFree(a
) => {
281 write
!(f
, "pointer to {} was dereferenced after this allocation got freed", a
)
283 PointerOutOfBounds { ptr, msg, allocation_size }
=> write
!(
285 "{} failed: pointer must be in-bounds at offset {}, \
286 but is outside bounds of {} which has size {}",
290 allocation_size
.bytes()
292 DanglingIntPointer(_
, CheckInAllocMsg
::NullPointerTest
) => {
293 write
!(f
, "NULL pointer is not allowed for this operation")
295 DanglingIntPointer(i
, msg
) => {
296 write
!(f
, "{} failed: 0x{:x} is not a valid pointer", msg
, i
)
298 AlignmentCheckFailed { required, has }
=> write
!(
300 "accessing memory with alignment {}, but alignment {} is required",
304 WriteToReadOnly(a
) => write
!(f
, "writing to {} which is read-only", a
),
305 DerefFunctionPointer(a
) => write
!(f
, "accessing {} which contains a function", a
),
306 ValidationFailure(ref err
) => write
!(f
, "type validation failed: {}", err
),
308 write
!(f
, "interpreting an invalid 8-bit value as a bool: 0x{:02x}", b
)
311 write
!(f
, "interpreting an invalid 32-bit value as a char: 0x{:08x}", c
)
313 InvalidTag(val
) => write
!(f
, "enum value has invalid tag: {}", val
),
314 InvalidFunctionPointer(p
) => {
315 write
!(f
, "using {} as function pointer but it does not point to a function", p
)
317 InvalidStr(err
) => write
!(f
, "this string is not valid UTF-8: {}", err
),
318 InvalidUninitBytes(Some(access
)) => write
!(
320 "reading {} byte{} of memory starting at {}, \
321 but {} byte{} {} uninitialized starting at {}, \
322 and this operation requires initialized memory",
323 access
.access_size
.bytes(),
324 pluralize
!(access
.access_size
.bytes()),
326 access
.uninit_size
.bytes(),
327 pluralize
!(access
.uninit_size
.bytes()),
328 if access
.uninit_size
.bytes() != 1 { "are" }
else { "is" }
,
331 InvalidUninitBytes(None
) => write
!(
333 "using uninitialized data, but this operation requires initialized memory"
335 DeadLocal
=> write
!(f
, "accessing a dead local variable"),
336 ScalarSizeMismatch { target_size, data_size }
=> write
!(
338 "scalar size mismatch: expected {} bytes but got {} bytes instead",
339 target_size
, data_size
345 /// Error information for when the program did something that might (or might not) be correct
346 /// to do according to the Rust spec, but due to limitations in the interpreter, the
347 /// operation could not be carried out. These limitations can differ between CTFE and the
348 /// Miri engine, e.g., CTFE does not support dereferencing pointers at integral addresses.
349 pub enum UnsupportedOpInfo
{
350 /// Free-form case. Only for errors that are never caught!
352 /// Could not find MIR for a function.
354 /// Encountered a pointer where we needed raw bytes.
357 // The variants below are only reachable from CTFE/const prop, miri will never emit them.
359 /// Encountered raw bytes where we needed a pointer.
361 /// Accessing thread local statics
362 ThreadLocalStatic(DefId
),
363 /// Accessing an unsupported extern static.
364 ReadExternStatic(DefId
),
367 impl fmt
::Display
for UnsupportedOpInfo
{
368 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
369 use UnsupportedOpInfo
::*;
371 Unsupported(ref msg
) => write
!(f
, "{}", msg
),
372 ReadExternStatic(did
) => write
!(f
, "cannot read from extern static ({:?})", did
),
373 NoMirFor(did
) => write
!(f
, "no MIR body is available for {:?}", did
),
374 ReadPointerAsBytes
=> write
!(f
, "unable to turn pointer into raw bytes",),
375 ReadBytesAsPointer
=> write
!(f
, "unable to turn bytes into a pointer"),
376 ThreadLocalStatic(did
) => write
!(f
, "cannot access thread local static ({:?})", did
),
381 /// Error information for when the program exhausted the resources granted to it
382 /// by the interpreter.
383 pub enum ResourceExhaustionInfo
{
384 /// The stack grew too big.
385 StackFrameLimitReached
,
386 /// The program ran for too long.
388 /// The exact limit is set by the `const_eval_limit` attribute.
392 impl fmt
::Display
for ResourceExhaustionInfo
{
393 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
394 use ResourceExhaustionInfo
::*;
396 StackFrameLimitReached
=> {
397 write
!(f
, "reached the configured maximum number of stack frames")
399 StepLimitReached
=> {
400 write
!(f
, "exceeded interpreter step limit (see `#[const_eval_limit]`)")
406 /// A trait to work around not having trait object upcasting.
407 pub trait AsAny
: Any
{
408 fn as_any(&self) -> &dyn Any
;
410 impl<T
: Any
> AsAny
for T
{
412 fn as_any(&self) -> &dyn Any
{
417 /// A trait for machine-specific errors (or other "machine stop" conditions).
418 pub trait MachineStopType
: AsAny
+ fmt
::Display
+ Send {}
419 impl MachineStopType
for String {}
421 impl dyn MachineStopType
{
423 pub fn downcast_ref
<T
: Any
>(&self) -> Option
<&T
> {
424 self.as_any().downcast_ref()
428 #[cfg(target_arch = "x86_64")]
429 static_assert_size
!(InterpError
<'_
>, 40);
431 pub enum InterpError
<'tcx
> {
432 /// The program caused undefined behavior.
433 UndefinedBehavior(UndefinedBehaviorInfo
<'tcx
>),
434 /// The program did something the interpreter does not support (some of these *might* be UB
435 /// but the interpreter is not sure).
436 Unsupported(UnsupportedOpInfo
),
437 /// The program was invalid (ill-typed, bad MIR, not sufficiently monomorphized, ...).
438 InvalidProgram(InvalidProgramInfo
<'tcx
>),
439 /// The program exhausted the interpreter's resources (stack/heap too big,
440 /// execution takes too long, ...).
441 ResourceExhaustion(ResourceExhaustionInfo
),
442 /// Stop execution for a machine-controlled reason. This is never raised by
443 /// the core engine itself.
444 MachineStop(Box
<dyn MachineStopType
>),
447 pub type InterpResult
<'tcx
, T
= ()> = Result
<T
, InterpErrorInfo
<'tcx
>>;
449 impl fmt
::Display
for InterpError
<'_
> {
450 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
453 Unsupported(ref msg
) => write
!(f
, "{}", msg
),
454 InvalidProgram(ref msg
) => write
!(f
, "{}", msg
),
455 UndefinedBehavior(ref msg
) => write
!(f
, "{}", msg
),
456 ResourceExhaustion(ref msg
) => write
!(f
, "{}", msg
),
457 MachineStop(ref msg
) => write
!(f
, "{}", msg
),
462 // Forward `Debug` to `Display`, so it does not look awful.
463 impl fmt
::Debug
for InterpError
<'_
> {
464 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
465 fmt
::Display
::fmt(self, f
)
469 impl InterpError
<'_
> {
470 /// Some errors allocate to be created as they contain free-form strings.
471 /// And sometimes we want to be sure that did not happen as it is a
472 /// waste of resources.
473 pub fn allocates(&self) -> bool
{
475 // Zero-sized boxes do not allocate.
476 InterpError
::MachineStop(b
) => mem
::size_of_val
::<dyn MachineStopType
>(&**b
) > 0,
477 InterpError
::Unsupported(UnsupportedOpInfo
::Unsupported(_
))
478 | InterpError
::UndefinedBehavior(UndefinedBehaviorInfo
::ValidationFailure(_
))
479 | InterpError
::UndefinedBehavior(UndefinedBehaviorInfo
::Ub(_
))
480 | InterpError
::UndefinedBehavior(UndefinedBehaviorInfo
::InvalidUninitBytes(Some(_
))) => {