]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_middle/src/mir/interpret/error.rs
New upstream version 1.53.0+dfsg1
[rustc.git] / compiler / rustc_middle / src / mir / interpret / error.rs
CommitLineData
1b1a35ee 1use super::{AllocId, ConstAlloc, Pointer, Scalar};
ea8adc8c 2
74b04a01 3use crate::mir::interpret::ConstValue;
3dfed10e 4use crate::ty::{layout, query::TyCtxtAt, tls, FnSig, Ty};
ea8adc8c 5
ba9703b0 6use rustc_data_structures::sync::Lock;
f9f354fc 7use rustc_errors::{pluralize, struct_span_err, DiagnosticBuilder, ErrorReported};
e1599b0c 8use rustc_macros::HashStable;
ba9703b0 9use rustc_session::CtfeBacktrace;
3dfed10e 10use rustc_span::def_id::DefId;
ba9703b0 11use rustc_target::abi::{Align, Size};
6a06907d 12use std::{any::Any, backtrace::Backtrace, fmt};
e1599b0c 13
3dfed10e 14#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
a1dfa0c6 15pub enum ErrorHandled {
ba9703b0
XL
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.
20 Linted,
a1dfa0c6
XL
21 /// Don't emit an error, the evaluation failed because the MIR was generic
22 /// and the substs didn't fully monomorphize it.
23 TooGeneric,
24}
25
1b1a35ee
XL
26impl From<ErrorReported> for ErrorHandled {
27 fn from(err: ErrorReported) -> ErrorHandled {
28 ErrorHandled::Reported(err)
29 }
30}
31
fc512014 32TrivialTypeFoldableAndLiftImpls! {
dc9dc135
XL
33 ErrorHandled,
34}
35
1b1a35ee
XL
36pub type EvalToAllocationRawResult<'tcx> = Result<ConstAlloc<'tcx>, ErrorHandled>;
37pub type EvalToConstValueResult<'tcx> = Result<ConstValue<'tcx>, ErrorHandled>;
8faf50e0 38
dc9dc135 39pub fn struct_error<'tcx>(tcx: TyCtxtAt<'tcx>, msg: &str) -> DiagnosticBuilder<'tcx> {
8faf50e0
XL
40 struct_span_err!(tcx.sess, tcx.span, E0080, "{}", msg)
41}
42
6a06907d
XL
43#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
44static_assert_size!(InterpErrorInfo<'_>, 8);
45
dc9dc135 46/// Packages the kind of error we got from the const code interpreter
60c5eb7d 47/// up with a Rust-level backtrace of where the error occurred.
cdc7bbd5
XL
48/// These should always be constructed by calling `.into()` on
49/// a `InterpError`. In `rustc_mir::interpret`, we have `throw_err_*`
416331ca 50/// macros for this.
60c5eb7d 51#[derive(Debug)]
6a06907d
XL
52pub struct InterpErrorInfo<'tcx>(Box<InterpErrorInfoInner<'tcx>>);
53
54#[derive(Debug)]
55struct InterpErrorInfoInner<'tcx> {
56 kind: InterpError<'tcx>,
dc9dc135 57 backtrace: Option<Box<Backtrace>>,
a1dfa0c6
XL
58}
59
416331ca
XL
60impl fmt::Display for InterpErrorInfo<'_> {
61 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
6a06907d 62 write!(f, "{}", self.0.kind)
416331ca
XL
63 }
64}
65
6a06907d 66impl InterpErrorInfo<'tcx> {
f9f354fc 67 pub fn print_backtrace(&self) {
6a06907d 68 if let Some(backtrace) = self.0.backtrace.as_ref() {
f9f354fc 69 print_backtrace(backtrace);
a1dfa0c6
XL
70 }
71 }
6a06907d
XL
72
73 pub fn into_kind(self) -> InterpError<'tcx> {
74 let InterpErrorInfo(box InterpErrorInfoInner { kind, .. }) = self;
75 kind
76 }
77
78 #[inline]
79 pub fn kind(&self) -> &InterpError<'tcx> {
80 &self.0.kind
81 }
a1dfa0c6
XL
82}
83
f9f354fc
XL
84fn print_backtrace(backtrace: &Backtrace) {
85 eprintln!("\n\nAn error occurred in miri:\n{}", backtrace);
ea8adc8c
XL
86}
87
74b04a01 88impl From<ErrorHandled> for InterpErrorInfo<'_> {
e1599b0c
XL
89 fn from(err: ErrorHandled) -> Self {
90 match err {
ba9703b0
XL
91 ErrorHandled::Reported(ErrorReported) | ErrorHandled::Linted => {
92 err_inval!(ReferencedConstant)
93 }
e1599b0c 94 ErrorHandled::TooGeneric => err_inval!(TooGeneric),
dfeec247
XL
95 }
96 .into()
e1599b0c
XL
97 }
98}
99
29967ef6
XL
100impl From<ErrorReported> for InterpErrorInfo<'_> {
101 fn from(err: ErrorReported) -> Self {
102 InterpError::InvalidProgram(InvalidProgramInfo::AlreadyReported(err)).into()
103 }
104}
105
416331ca
XL
106impl<'tcx> From<InterpError<'tcx>> for InterpErrorInfo<'tcx> {
107 fn from(kind: InterpError<'tcx>) -> Self {
3dfed10e
XL
108 let capture_backtrace = tls::with_opt(|tcx| {
109 if let Some(tcx) = tcx {
110 *Lock::borrow(&tcx.sess.ctfe_backtrace)
ba9703b0
XL
111 } else {
112 CtfeBacktrace::Disabled
113 }
114 });
a1dfa0c6 115
ba9703b0
XL
116 let backtrace = match capture_backtrace {
117 CtfeBacktrace::Disabled => None,
f9f354fc 118 CtfeBacktrace::Capture => Some(Box::new(Backtrace::force_capture())),
ba9703b0
XL
119 CtfeBacktrace::Immediate => {
120 // Print it now.
f9f354fc
XL
121 let backtrace = Backtrace::force_capture();
122 print_backtrace(&backtrace);
ba9703b0 123 None
dfeec247 124 }
a1dfa0c6 125 };
ba9703b0 126
6a06907d 127 InterpErrorInfo(Box::new(InterpErrorInfoInner { kind, backtrace }))
ea8adc8c
XL
128 }
129}
130
e1599b0c
XL
131/// Error information for when the program we executed turned out not to actually be a valid
132/// program. This cannot happen in stand-alone Miri, but it can happen during CTFE/ConstProp
133/// where we work on generic code or execution does not have all information available.
416331ca
XL
134pub enum InvalidProgramInfo<'tcx> {
135 /// Resolution can fail if we are in a too generic context.
136 TooGeneric,
137 /// Cannot compute this constant because it depends on another one
138 /// which already produced an error.
139 ReferencedConstant,
29967ef6
XL
140 /// Abort in case errors are already reported.
141 AlreadyReported(ErrorReported),
416331ca
XL
142 /// An error occurred during layout computation.
143 Layout(layout::LayoutError<'tcx>),
ba9703b0
XL
144 /// An invalid transmute happened.
145 TransmuteSizeDiff(Ty<'tcx>, Ty<'tcx>),
5869c6ff
XL
146 /// SizeOf of unsized type was requested.
147 SizeOfUnsizedType(Ty<'tcx>),
416331ca 148}
b7449926 149
f9f354fc 150impl fmt::Display for InvalidProgramInfo<'_> {
416331ca
XL
151 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
152 use InvalidProgramInfo::*;
153 match self {
dfeec247
XL
154 TooGeneric => write!(f, "encountered overly generic constant"),
155 ReferencedConstant => write!(f, "referenced constant has errors"),
29967ef6 156 AlreadyReported(ErrorReported) => {
ba9703b0
XL
157 write!(f, "encountered constants with type errors, stopping evaluation")
158 }
dfeec247 159 Layout(ref err) => write!(f, "{}", err),
ba9703b0
XL
160 TransmuteSizeDiff(from_ty, to_ty) => write!(
161 f,
162 "transmuting `{}` to `{}` is not possible, because these types do not have the same size",
163 from_ty, to_ty
164 ),
5869c6ff 165 SizeOfUnsizedType(ty) => write!(f, "size_of called on unsized type `{}`", ty),
416331ca
XL
166 }
167 }
168}
169
f9f354fc 170/// Details of why a pointer had to be in-bounds.
3dfed10e 171#[derive(Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)]
f9f354fc
XL
172pub enum CheckInAllocMsg {
173 MemoryAccessTest,
174 NullPointerTest,
175 PointerArithmeticTest,
176 InboundsTest,
177}
178
179impl fmt::Display for CheckInAllocMsg {
180 /// When this is printed as an error the context looks like this
181 /// "{test name} failed: pointer must be in-bounds at offset..."
182 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
183 write!(
184 f,
185 "{}",
186 match *self {
187 CheckInAllocMsg::MemoryAccessTest => "memory access",
188 CheckInAllocMsg::NullPointerTest => "NULL pointer test",
189 CheckInAllocMsg::PointerArithmeticTest => "pointer arithmetic",
190 CheckInAllocMsg::InboundsTest => "inbounds test",
191 }
192 )
193 }
194}
195
196/// Details of an access to uninitialized bytes where it is not allowed.
197#[derive(Debug)]
198pub struct UninitBytesAccess {
199 /// Location of the original memory access.
200 pub access_ptr: Pointer,
201 /// Size of the original memory access.
202 pub access_size: Size,
203 /// Location of the first uninitialized byte that was accessed.
204 pub uninit_ptr: Pointer,
205 /// Number of consecutive uninitialized bytes that were accessed.
206 pub uninit_size: Size,
207}
208
e1599b0c 209/// Error information for when the program caused Undefined Behavior.
f9f354fc 210pub enum UndefinedBehaviorInfo<'tcx> {
416331ca
XL
211 /// Free-form case. Only for errors that are never caught!
212 Ub(String),
416331ca
XL
213 /// Unreachable code was executed.
214 Unreachable,
60c5eb7d 215 /// A slice/array index projection went out-of-bounds.
ba9703b0
XL
216 BoundsCheckFailed {
217 len: u64,
218 index: u64,
219 },
60c5eb7d
XL
220 /// Something was divided by 0 (x / 0).
221 DivisionByZero,
222 /// Something was "remainded" by 0 (x % 0).
223 RemainderByZero,
224 /// Overflowing inbounds pointer arithmetic.
225 PointerArithOverflow,
74b04a01
XL
226 /// Invalid metadata in a wide pointer (using `str` to avoid allocations).
227 InvalidMeta(&'static str),
f9f354fc
XL
228 /// Invalid drop function in vtable.
229 InvalidDropFn(FnSig<'tcx>),
ba9703b0
XL
230 /// Reading a C string that does not end within its allocation.
231 UnterminatedCString(Pointer),
232 /// Dereferencing a dangling pointer after it got freed.
233 PointerUseAfterFree(AllocId),
234 /// Used a pointer outside the bounds it is valid for.
235 PointerOutOfBounds {
236 ptr: Pointer,
237 msg: CheckInAllocMsg,
238 allocation_size: Size,
239 },
f9f354fc
XL
240 /// Using an integer as a pointer in the wrong way.
241 DanglingIntPointer(u64, CheckInAllocMsg),
ba9703b0
XL
242 /// Used a pointer with bad alignment.
243 AlignmentCheckFailed {
244 required: Align,
245 has: Align,
246 },
ba9703b0
XL
247 /// Writing to read-only memory.
248 WriteToReadOnly(AllocId),
ba9703b0
XL
249 // Trying to access the data behind a function pointer.
250 DerefFunctionPointer(AllocId),
251 /// The value validity check found a problem.
252 /// Should only be thrown by `validity.rs` and always point out which part of the value
253 /// is the problem.
254 ValidationFailure(String),
255 /// Using a non-boolean `u8` as bool.
256 InvalidBool(u8),
257 /// Using a non-character `u32` as character.
258 InvalidChar(u32),
f035d41b
XL
259 /// The tag of an enum does not encode an actual discriminant.
260 InvalidTag(Scalar),
f9f354fc
XL
261 /// Using a pointer-not-to-a-function as function pointer.
262 InvalidFunctionPointer(Pointer),
263 /// Using a string that is not valid UTF-8,
264 InvalidStr(std::str::Utf8Error),
ba9703b0 265 /// Using uninitialized data where it is not allowed.
6a06907d 266 InvalidUninitBytes(Option<UninitBytesAccess>),
ba9703b0
XL
267 /// Working with a local that is not currently live.
268 DeadLocal,
f9f354fc
XL
269 /// Data size is not equal to target size.
270 ScalarSizeMismatch {
271 target_size: u64,
272 data_size: u64,
273 },
416331ca 274}
48663c56 275
f9f354fc 276impl fmt::Display for UndefinedBehaviorInfo<'_> {
416331ca
XL
277 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
278 use UndefinedBehaviorInfo::*;
279 match self {
ba9703b0 280 Ub(msg) => write!(f, "{}", msg),
dfeec247 281 Unreachable => write!(f, "entering unreachable code"),
f9f354fc
XL
282 BoundsCheckFailed { ref len, ref index } => {
283 write!(f, "indexing out of bounds: the len is {} but the index is {}", len, index)
284 }
dfeec247
XL
285 DivisionByZero => write!(f, "dividing by zero"),
286 RemainderByZero => write!(f, "calculating the remainder with a divisor of zero"),
287 PointerArithOverflow => write!(f, "overflowing in-bounds pointer arithmetic"),
74b04a01 288 InvalidMeta(msg) => write!(f, "invalid metadata in wide pointer: {}", msg),
f9f354fc
XL
289 InvalidDropFn(sig) => write!(
290 f,
291 "invalid drop function signature: got {}, expected exactly one argument which must be a pointer type",
292 sig
293 ),
ba9703b0
XL
294 UnterminatedCString(p) => write!(
295 f,
f9f354fc 296 "reading a null-terminated string starting at {} with no null found before end of allocation",
ba9703b0
XL
297 p,
298 ),
299 PointerUseAfterFree(a) => {
f9f354fc 300 write!(f, "pointer to {} was dereferenced after this allocation got freed", a)
ba9703b0
XL
301 }
302 PointerOutOfBounds { ptr, msg, allocation_size } => write!(
303 f,
304 "{} failed: pointer must be in-bounds at offset {}, \
305 but is outside bounds of {} which has size {}",
306 msg,
307 ptr.offset.bytes(),
308 ptr.alloc_id,
309 allocation_size.bytes()
310 ),
f9f354fc
XL
311 DanglingIntPointer(_, CheckInAllocMsg::NullPointerTest) => {
312 write!(f, "NULL pointer is not allowed for this operation")
313 }
314 DanglingIntPointer(i, msg) => {
315 write!(f, "{} failed: 0x{:x} is not a valid pointer", msg, i)
316 }
ba9703b0
XL
317 AlignmentCheckFailed { required, has } => write!(
318 f,
319 "accessing memory with alignment {}, but alignment {} is required",
320 has.bytes(),
321 required.bytes()
322 ),
f9f354fc
XL
323 WriteToReadOnly(a) => write!(f, "writing to {} which is read-only", a),
324 DerefFunctionPointer(a) => write!(f, "accessing {} which contains a function", a),
325 ValidationFailure(ref err) => write!(f, "type validation failed: {}", err),
326 InvalidBool(b) => {
327 write!(f, "interpreting an invalid 8-bit value as a bool: 0x{:02x}", b)
328 }
329 InvalidChar(c) => {
330 write!(f, "interpreting an invalid 32-bit value as a char: 0x{:08x}", c)
331 }
f035d41b 332 InvalidTag(val) => write!(f, "enum value has invalid tag: {}", val),
ba9703b0 333 InvalidFunctionPointer(p) => {
f9f354fc 334 write!(f, "using {} as function pointer but it does not point to a function", p)
ba9703b0 335 }
f9f354fc
XL
336 InvalidStr(err) => write!(f, "this string is not valid UTF-8: {}", err),
337 InvalidUninitBytes(Some(access)) => write!(
ba9703b0 338 f,
f9f354fc
XL
339 "reading {} byte{} of memory starting at {}, \
340 but {} byte{} {} uninitialized starting at {}, \
341 and this operation requires initialized memory",
342 access.access_size.bytes(),
343 pluralize!(access.access_size.bytes()),
344 access.access_ptr,
345 access.uninit_size.bytes(),
346 pluralize!(access.uninit_size.bytes()),
347 if access.uninit_size.bytes() != 1 { "are" } else { "is" },
348 access.uninit_ptr,
ba9703b0 349 ),
f9f354fc 350 InvalidUninitBytes(None) => write!(
ba9703b0
XL
351 f,
352 "using uninitialized data, but this operation requires initialized memory"
353 ),
354 DeadLocal => write!(f, "accessing a dead local variable"),
f9f354fc
XL
355 ScalarSizeMismatch { target_size, data_size } => write!(
356 f,
357 "scalar size mismatch: expected {} bytes but got {} bytes instead",
358 target_size, data_size
359 ),
416331ca
XL
360 }
361 }
362}
363
e1599b0c
XL
364/// Error information for when the program did something that might (or might not) be correct
365/// to do according to the Rust spec, but due to limitations in the interpreter, the
366/// operation could not be carried out. These limitations can differ between CTFE and the
f9f354fc 367/// Miri engine, e.g., CTFE does not support dereferencing pointers at integral addresses.
ba9703b0 368pub enum UnsupportedOpInfo {
416331ca
XL
369 /// Free-form case. Only for errors that are never caught!
370 Unsupported(String),
ba9703b0
XL
371 /// Could not find MIR for a function.
372 NoMirFor(DefId),
373 /// Encountered a pointer where we needed raw bytes.
ea8adc8c 374 ReadPointerAsBytes,
f9f354fc
XL
375 //
376 // The variants below are only reachable from CTFE/const prop, miri will never emit them.
377 //
ba9703b0 378 /// Encountered raw bytes where we needed a pointer.
ea8adc8c 379 ReadBytesAsPointer,
f9f354fc
XL
380 /// Accessing thread local statics
381 ThreadLocalStatic(DefId),
3dfed10e
XL
382 /// Accessing an unsupported extern static.
383 ReadExternStatic(DefId),
ea8adc8c
XL
384}
385
f9f354fc 386impl fmt::Display for UnsupportedOpInfo {
a1dfa0c6 387 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
416331ca
XL
388 use UnsupportedOpInfo::*;
389 match self {
dfeec247 390 Unsupported(ref msg) => write!(f, "{}", msg),
3dfed10e 391 ReadExternStatic(did) => write!(f, "cannot read from extern static ({:?})", did),
ba9703b0
XL
392 NoMirFor(did) => write!(f, "no MIR body is available for {:?}", did),
393 ReadPointerAsBytes => write!(f, "unable to turn pointer into raw bytes",),
394 ReadBytesAsPointer => write!(f, "unable to turn bytes into a pointer"),
f9f354fc 395 ThreadLocalStatic(did) => write!(f, "cannot access thread local static ({:?})", did),
416331ca
XL
396 }
397 }
398}
399
e1599b0c
XL
400/// Error information for when the program exhausted the resources granted to it
401/// by the interpreter.
416331ca
XL
402pub enum ResourceExhaustionInfo {
403 /// The stack grew too big.
404 StackFrameLimitReached,
ba9703b0
XL
405 /// The program ran for too long.
406 ///
407 /// The exact limit is set by the `const_eval_limit` attribute.
408 StepLimitReached,
416331ca
XL
409}
410
f9f354fc 411impl fmt::Display for ResourceExhaustionInfo {
416331ca
XL
412 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
413 use ResourceExhaustionInfo::*;
414 match self {
dfeec247
XL
415 StackFrameLimitReached => {
416 write!(f, "reached the configured maximum number of stack frames")
417 }
ba9703b0
XL
418 StepLimitReached => {
419 write!(f, "exceeded interpreter step limit (see `#[const_eval_limit]`)")
420 }
416331ca
XL
421 }
422 }
423}
424
ba9703b0
XL
425/// A trait to work around not having trait object upcasting.
426pub trait AsAny: Any {
427 fn as_any(&self) -> &dyn Any;
428}
ba9703b0
XL
429impl<T: Any> AsAny for T {
430 #[inline(always)]
431 fn as_any(&self) -> &dyn Any {
432 self
433 }
434}
435
436/// A trait for machine-specific errors (or other "machine stop" conditions).
f9f354fc 437pub trait MachineStopType: AsAny + fmt::Display + Send {}
ba9703b0
XL
438impl MachineStopType for String {}
439
440impl dyn MachineStopType {
441 #[inline(always)]
442 pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
443 self.as_any().downcast_ref()
444 }
445}
446
6a06907d
XL
447#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
448static_assert_size!(InterpError<'_>, 72);
f9f354fc 449
416331ca 450pub enum InterpError<'tcx> {
416331ca 451 /// The program caused undefined behavior.
f9f354fc 452 UndefinedBehavior(UndefinedBehaviorInfo<'tcx>),
416331ca
XL
453 /// The program did something the interpreter does not support (some of these *might* be UB
454 /// but the interpreter is not sure).
ba9703b0 455 Unsupported(UnsupportedOpInfo),
60c5eb7d 456 /// The program was invalid (ill-typed, bad MIR, not sufficiently monomorphized, ...).
416331ca
XL
457 InvalidProgram(InvalidProgramInfo<'tcx>),
458 /// The program exhausted the interpreter's resources (stack/heap too big,
60c5eb7d 459 /// execution takes too long, ...).
416331ca 460 ResourceExhaustion(ResourceExhaustionInfo),
60c5eb7d
XL
461 /// Stop execution for a machine-controlled reason. This is never raised by
462 /// the core engine itself.
ba9703b0 463 MachineStop(Box<dyn MachineStopType>),
416331ca
XL
464}
465
466pub type InterpResult<'tcx, T = ()> = Result<T, InterpErrorInfo<'tcx>>;
467
468impl fmt::Display for InterpError<'_> {
469 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f9f354fc
XL
470 use InterpError::*;
471 match *self {
472 Unsupported(ref msg) => write!(f, "{}", msg),
473 InvalidProgram(ref msg) => write!(f, "{}", msg),
474 UndefinedBehavior(ref msg) => write!(f, "{}", msg),
475 ResourceExhaustion(ref msg) => write!(f, "{}", msg),
476 MachineStop(ref msg) => write!(f, "{}", msg),
477 }
416331ca
XL
478 }
479}
480
f9f354fc 481// Forward `Debug` to `Display`, so it does not look awful.
416331ca
XL
482impl fmt::Debug for InterpError<'_> {
483 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f9f354fc 484 fmt::Display::fmt(self, f)
74b04a01
XL
485 }
486}
487
488impl InterpError<'_> {
6a06907d
XL
489 /// Some errors to string formatting even if the error is never printed.
490 /// To avoid performance issues, there are places where we want to be sure to never raise these formatting errors,
491 /// so this method lets us detect them and `bug!` on unexpected errors.
492 pub fn formatted_string(&self) -> bool {
74b04a01 493 match self {
ba9703b0
XL
494 InterpError::Unsupported(UnsupportedOpInfo::Unsupported(_))
495 | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::ValidationFailure(_))
6a06907d 496 | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::Ub(_)) => true,
74b04a01 497 _ => false,
ea8adc8c
XL
498 }
499 }
500}