1 use super::{AllocId, Pointer, RawConst, 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 CloneTypeFoldableAndLiftImpls
! {
30 pub type ConstEvalRawResult
<'tcx
> = Result
<RawConst
<'tcx
>, ErrorHandled
>;
31 pub type ConstEvalResult
<'tcx
> = Result
<ConstValue
<'tcx
>, ErrorHandled
>;
33 pub fn struct_error
<'tcx
>(tcx
: TyCtxtAt
<'tcx
>, msg
: &str) -> DiagnosticBuilder
<'tcx
> {
34 struct_span_err
!(tcx
.sess
, tcx
.span
, E0080
, "{}", msg
)
37 /// Packages the kind of error we got from the const code interpreter
38 /// up with a Rust-level backtrace of where the error occurred.
39 /// Thsese should always be constructed by calling `.into()` on
40 /// a `InterpError`. In `librustc_mir::interpret`, we have `throw_err_*`
43 pub struct InterpErrorInfo
<'tcx
> {
44 pub kind
: InterpError
<'tcx
>,
45 backtrace
: Option
<Box
<Backtrace
>>,
48 impl fmt
::Display
for InterpErrorInfo
<'_
> {
49 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
50 write
!(f
, "{}", self.kind
)
54 impl InterpErrorInfo
<'_
> {
55 pub fn print_backtrace(&self) {
56 if let Some(backtrace
) = self.backtrace
.as_ref() {
57 print_backtrace(backtrace
);
62 fn print_backtrace(backtrace
: &Backtrace
) {
63 eprintln
!("\n\nAn error occurred in miri:\n{}", backtrace
);
66 impl From
<ErrorHandled
> for InterpErrorInfo
<'_
> {
67 fn from(err
: ErrorHandled
) -> Self {
69 ErrorHandled
::Reported(ErrorReported
) | ErrorHandled
::Linted
=> {
70 err_inval
!(ReferencedConstant
)
72 ErrorHandled
::TooGeneric
=> err_inval
!(TooGeneric
),
78 impl<'tcx
> From
<InterpError
<'tcx
>> for InterpErrorInfo
<'tcx
> {
79 fn from(kind
: InterpError
<'tcx
>) -> Self {
80 let capture_backtrace
= tls
::with_opt(|tcx
| {
81 if let Some(tcx
) = tcx
{
82 *Lock
::borrow(&tcx
.sess
.ctfe_backtrace
)
84 CtfeBacktrace
::Disabled
88 let backtrace
= match capture_backtrace
{
89 CtfeBacktrace
::Disabled
=> None
,
90 CtfeBacktrace
::Capture
=> Some(Box
::new(Backtrace
::force_capture())),
91 CtfeBacktrace
::Immediate
=> {
93 let backtrace
= Backtrace
::force_capture();
94 print_backtrace(&backtrace
);
99 InterpErrorInfo { kind, backtrace }
103 /// Error information for when the program we executed turned out not to actually be a valid
104 /// program. This cannot happen in stand-alone Miri, but it can happen during CTFE/ConstProp
105 /// where we work on generic code or execution does not have all information available.
106 pub enum InvalidProgramInfo
<'tcx
> {
107 /// Resolution can fail if we are in a too generic context.
109 /// Cannot compute this constant because it depends on another one
110 /// which already produced an error.
112 /// Abort in case type errors are reached.
113 TypeckError(ErrorReported
),
114 /// An error occurred during layout computation.
115 Layout(layout
::LayoutError
<'tcx
>),
116 /// An invalid transmute happened.
117 TransmuteSizeDiff(Ty
<'tcx
>, Ty
<'tcx
>),
120 impl fmt
::Display
for InvalidProgramInfo
<'_
> {
121 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
122 use InvalidProgramInfo
::*;
124 TooGeneric
=> write
!(f
, "encountered overly generic constant"),
125 ReferencedConstant
=> write
!(f
, "referenced constant has errors"),
126 TypeckError(ErrorReported
) => {
127 write
!(f
, "encountered constants with type errors, stopping evaluation")
129 Layout(ref err
) => write
!(f
, "{}", err
),
130 TransmuteSizeDiff(from_ty
, to_ty
) => write
!(
132 "transmuting `{}` to `{}` is not possible, because these types do not have the same size",
139 /// Details of why a pointer had to be in-bounds.
140 #[derive(Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)]
141 pub enum CheckInAllocMsg
{
144 PointerArithmeticTest
,
148 impl fmt
::Display
for CheckInAllocMsg
{
149 /// When this is printed as an error the context looks like this
150 /// "{test name} failed: pointer must be in-bounds at offset..."
151 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
156 CheckInAllocMsg
::MemoryAccessTest
=> "memory access",
157 CheckInAllocMsg
::NullPointerTest
=> "NULL pointer test",
158 CheckInAllocMsg
::PointerArithmeticTest
=> "pointer arithmetic",
159 CheckInAllocMsg
::InboundsTest
=> "inbounds test",
165 /// Details of an access to uninitialized bytes where it is not allowed.
167 pub struct UninitBytesAccess
{
168 /// Location of the original memory access.
169 pub access_ptr
: Pointer
,
170 /// Size of the original memory access.
171 pub access_size
: Size
,
172 /// Location of the first uninitialized byte that was accessed.
173 pub uninit_ptr
: Pointer
,
174 /// Number of consecutive uninitialized bytes that were accessed.
175 pub uninit_size
: Size
,
178 /// Error information for when the program caused Undefined Behavior.
179 pub enum UndefinedBehaviorInfo
<'tcx
> {
180 /// Free-form case. Only for errors that are never caught!
182 /// Unreachable code was executed.
184 /// A slice/array index projection went out-of-bounds.
189 /// Something was divided by 0 (x / 0).
191 /// Something was "remainded" by 0 (x % 0).
193 /// Overflowing inbounds pointer arithmetic.
194 PointerArithOverflow
,
195 /// Invalid metadata in a wide pointer (using `str` to avoid allocations).
196 InvalidMeta(&'
static str),
197 /// Invalid drop function in vtable.
198 InvalidDropFn(FnSig
<'tcx
>),
199 /// Reading a C string that does not end within its allocation.
200 UnterminatedCString(Pointer
),
201 /// Dereferencing a dangling pointer after it got freed.
202 PointerUseAfterFree(AllocId
),
203 /// Used a pointer outside the bounds it is valid for.
206 msg
: CheckInAllocMsg
,
207 allocation_size
: Size
,
209 /// Using an integer as a pointer in the wrong way.
210 DanglingIntPointer(u64, CheckInAllocMsg
),
211 /// Used a pointer with bad alignment.
212 AlignmentCheckFailed
{
216 /// Writing to read-only memory.
217 WriteToReadOnly(AllocId
),
218 // Trying to access the data behind a function pointer.
219 DerefFunctionPointer(AllocId
),
220 /// The value validity check found a problem.
221 /// Should only be thrown by `validity.rs` and always point out which part of the value
223 ValidationFailure(String
),
224 /// Using a non-boolean `u8` as bool.
226 /// Using a non-character `u32` as character.
228 /// The tag of an enum does not encode an actual discriminant.
230 /// Using a pointer-not-to-a-function as function pointer.
231 InvalidFunctionPointer(Pointer
),
232 /// Using a string that is not valid UTF-8,
233 InvalidStr(std
::str::Utf8Error
),
234 /// Using uninitialized data where it is not allowed.
235 InvalidUninitBytes(Option
<Box
<UninitBytesAccess
>>),
236 /// Working with a local that is not currently live.
238 /// Data size is not equal to target size.
245 impl fmt
::Display
for UndefinedBehaviorInfo
<'_
> {
246 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
247 use UndefinedBehaviorInfo
::*;
249 Ub(msg
) => write
!(f
, "{}", msg
),
250 Unreachable
=> write
!(f
, "entering unreachable code"),
251 BoundsCheckFailed { ref len, ref index }
=> {
252 write
!(f
, "indexing out of bounds: the len is {} but the index is {}", len
, index
)
254 DivisionByZero
=> write
!(f
, "dividing by zero"),
255 RemainderByZero
=> write
!(f
, "calculating the remainder with a divisor of zero"),
256 PointerArithOverflow
=> write
!(f
, "overflowing in-bounds pointer arithmetic"),
257 InvalidMeta(msg
) => write
!(f
, "invalid metadata in wide pointer: {}", msg
),
258 InvalidDropFn(sig
) => write
!(
260 "invalid drop function signature: got {}, expected exactly one argument which must be a pointer type",
263 UnterminatedCString(p
) => write
!(
265 "reading a null-terminated string starting at {} with no null found before end of allocation",
268 PointerUseAfterFree(a
) => {
269 write
!(f
, "pointer to {} was dereferenced after this allocation got freed", a
)
271 PointerOutOfBounds { ptr, msg, allocation_size }
=> write
!(
273 "{} failed: pointer must be in-bounds at offset {}, \
274 but is outside bounds of {} which has size {}",
278 allocation_size
.bytes()
280 DanglingIntPointer(_
, CheckInAllocMsg
::NullPointerTest
) => {
281 write
!(f
, "NULL pointer is not allowed for this operation")
283 DanglingIntPointer(i
, msg
) => {
284 write
!(f
, "{} failed: 0x{:x} is not a valid pointer", msg
, i
)
286 AlignmentCheckFailed { required, has }
=> write
!(
288 "accessing memory with alignment {}, but alignment {} is required",
292 WriteToReadOnly(a
) => write
!(f
, "writing to {} which is read-only", a
),
293 DerefFunctionPointer(a
) => write
!(f
, "accessing {} which contains a function", a
),
294 ValidationFailure(ref err
) => write
!(f
, "type validation failed: {}", err
),
296 write
!(f
, "interpreting an invalid 8-bit value as a bool: 0x{:02x}", b
)
299 write
!(f
, "interpreting an invalid 32-bit value as a char: 0x{:08x}", c
)
301 InvalidTag(val
) => write
!(f
, "enum value has invalid tag: {}", val
),
302 InvalidFunctionPointer(p
) => {
303 write
!(f
, "using {} as function pointer but it does not point to a function", p
)
305 InvalidStr(err
) => write
!(f
, "this string is not valid UTF-8: {}", err
),
306 InvalidUninitBytes(Some(access
)) => write
!(
308 "reading {} byte{} of memory starting at {}, \
309 but {} byte{} {} uninitialized starting at {}, \
310 and this operation requires initialized memory",
311 access
.access_size
.bytes(),
312 pluralize
!(access
.access_size
.bytes()),
314 access
.uninit_size
.bytes(),
315 pluralize
!(access
.uninit_size
.bytes()),
316 if access
.uninit_size
.bytes() != 1 { "are" }
else { "is" }
,
319 InvalidUninitBytes(None
) => write
!(
321 "using uninitialized data, but this operation requires initialized memory"
323 DeadLocal
=> write
!(f
, "accessing a dead local variable"),
324 ScalarSizeMismatch { target_size, data_size }
=> write
!(
326 "scalar size mismatch: expected {} bytes but got {} bytes instead",
327 target_size
, data_size
333 /// Error information for when the program did something that might (or might not) be correct
334 /// to do according to the Rust spec, but due to limitations in the interpreter, the
335 /// operation could not be carried out. These limitations can differ between CTFE and the
336 /// Miri engine, e.g., CTFE does not support dereferencing pointers at integral addresses.
337 pub enum UnsupportedOpInfo
{
338 /// Free-form case. Only for errors that are never caught!
340 /// Could not find MIR for a function.
342 /// Encountered a pointer where we needed raw bytes.
345 // The variants below are only reachable from CTFE/const prop, miri will never emit them.
347 /// Encountered raw bytes where we needed a pointer.
349 /// Accessing thread local statics
350 ThreadLocalStatic(DefId
),
351 /// Accessing an unsupported extern static.
352 ReadExternStatic(DefId
),
355 impl fmt
::Display
for UnsupportedOpInfo
{
356 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
357 use UnsupportedOpInfo
::*;
359 Unsupported(ref msg
) => write
!(f
, "{}", msg
),
360 ReadExternStatic(did
) => write
!(f
, "cannot read from extern static ({:?})", did
),
361 NoMirFor(did
) => write
!(f
, "no MIR body is available for {:?}", did
),
362 ReadPointerAsBytes
=> write
!(f
, "unable to turn pointer into raw bytes",),
363 ReadBytesAsPointer
=> write
!(f
, "unable to turn bytes into a pointer"),
364 ThreadLocalStatic(did
) => write
!(f
, "cannot access thread local static ({:?})", did
),
369 /// Error information for when the program exhausted the resources granted to it
370 /// by the interpreter.
371 pub enum ResourceExhaustionInfo
{
372 /// The stack grew too big.
373 StackFrameLimitReached
,
374 /// The program ran for too long.
376 /// The exact limit is set by the `const_eval_limit` attribute.
380 impl fmt
::Display
for ResourceExhaustionInfo
{
381 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
382 use ResourceExhaustionInfo
::*;
384 StackFrameLimitReached
=> {
385 write
!(f
, "reached the configured maximum number of stack frames")
387 StepLimitReached
=> {
388 write
!(f
, "exceeded interpreter step limit (see `#[const_eval_limit]`)")
394 /// A trait to work around not having trait object upcasting.
395 pub trait AsAny
: Any
{
396 fn as_any(&self) -> &dyn Any
;
398 impl<T
: Any
> AsAny
for T
{
400 fn as_any(&self) -> &dyn Any
{
405 /// A trait for machine-specific errors (or other "machine stop" conditions).
406 pub trait MachineStopType
: AsAny
+ fmt
::Display
+ Send {}
407 impl MachineStopType
for String {}
409 impl dyn MachineStopType
{
411 pub fn downcast_ref
<T
: Any
>(&self) -> Option
<&T
> {
412 self.as_any().downcast_ref()
416 #[cfg(target_arch = "x86_64")]
417 static_assert_size
!(InterpError
<'_
>, 40);
419 pub enum InterpError
<'tcx
> {
420 /// The program caused undefined behavior.
421 UndefinedBehavior(UndefinedBehaviorInfo
<'tcx
>),
422 /// The program did something the interpreter does not support (some of these *might* be UB
423 /// but the interpreter is not sure).
424 Unsupported(UnsupportedOpInfo
),
425 /// The program was invalid (ill-typed, bad MIR, not sufficiently monomorphized, ...).
426 InvalidProgram(InvalidProgramInfo
<'tcx
>),
427 /// The program exhausted the interpreter's resources (stack/heap too big,
428 /// execution takes too long, ...).
429 ResourceExhaustion(ResourceExhaustionInfo
),
430 /// Stop execution for a machine-controlled reason. This is never raised by
431 /// the core engine itself.
432 MachineStop(Box
<dyn MachineStopType
>),
435 pub type InterpResult
<'tcx
, T
= ()> = Result
<T
, InterpErrorInfo
<'tcx
>>;
437 impl fmt
::Display
for InterpError
<'_
> {
438 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
441 Unsupported(ref msg
) => write
!(f
, "{}", msg
),
442 InvalidProgram(ref msg
) => write
!(f
, "{}", msg
),
443 UndefinedBehavior(ref msg
) => write
!(f
, "{}", msg
),
444 ResourceExhaustion(ref msg
) => write
!(f
, "{}", msg
),
445 MachineStop(ref msg
) => write
!(f
, "{}", msg
),
450 // Forward `Debug` to `Display`, so it does not look awful.
451 impl fmt
::Debug
for InterpError
<'_
> {
452 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
453 fmt
::Display
::fmt(self, f
)
457 impl InterpError
<'_
> {
458 /// Some errors allocate to be created as they contain free-form strings.
459 /// And sometimes we want to be sure that did not happen as it is a
460 /// waste of resources.
461 pub fn allocates(&self) -> bool
{
463 // Zero-sized boxes do not allocate.
464 InterpError
::MachineStop(b
) => mem
::size_of_val
::<dyn MachineStopType
>(&**b
) > 0,
465 InterpError
::Unsupported(UnsupportedOpInfo
::Unsupported(_
))
466 | InterpError
::UndefinedBehavior(UndefinedBehaviorInfo
::ValidationFailure(_
))
467 | InterpError
::UndefinedBehavior(UndefinedBehaviorInfo
::Ub(_
))
468 | InterpError
::UndefinedBehavior(UndefinedBehaviorInfo
::InvalidUninitBytes(Some(_
))) => {