]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_middle/src/mir/interpret/error.rs
New upstream version 1.49.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};
f9f354fc 12use std::{any::Any, backtrace::Backtrace, fmt, mem};
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
3dfed10e 32CloneTypeFoldableAndLiftImpls! {
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
dc9dc135 43/// Packages the kind of error we got from the const code interpreter
60c5eb7d 44/// up with a Rust-level backtrace of where the error occurred.
dc9dc135 45/// Thsese should always be constructed by calling `.into()` on
416331ca
XL
46/// a `InterpError`. In `librustc_mir::interpret`, we have `throw_err_*`
47/// macros for this.
60c5eb7d 48#[derive(Debug)]
dc9dc135 49pub struct InterpErrorInfo<'tcx> {
416331ca 50 pub kind: InterpError<'tcx>,
dc9dc135 51 backtrace: Option<Box<Backtrace>>,
a1dfa0c6
XL
52}
53
416331ca
XL
54impl fmt::Display for InterpErrorInfo<'_> {
55 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56 write!(f, "{}", self.kind)
57 }
58}
59
60impl InterpErrorInfo<'_> {
f9f354fc
XL
61 pub fn print_backtrace(&self) {
62 if let Some(backtrace) = self.backtrace.as_ref() {
63 print_backtrace(backtrace);
a1dfa0c6
XL
64 }
65 }
66}
67
f9f354fc
XL
68fn print_backtrace(backtrace: &Backtrace) {
69 eprintln!("\n\nAn error occurred in miri:\n{}", backtrace);
ea8adc8c
XL
70}
71
74b04a01 72impl From<ErrorHandled> for InterpErrorInfo<'_> {
e1599b0c
XL
73 fn from(err: ErrorHandled) -> Self {
74 match err {
ba9703b0
XL
75 ErrorHandled::Reported(ErrorReported) | ErrorHandled::Linted => {
76 err_inval!(ReferencedConstant)
77 }
e1599b0c 78 ErrorHandled::TooGeneric => err_inval!(TooGeneric),
dfeec247
XL
79 }
80 .into()
e1599b0c
XL
81 }
82}
83
29967ef6
XL
84impl From<ErrorReported> for InterpErrorInfo<'_> {
85 fn from(err: ErrorReported) -> Self {
86 InterpError::InvalidProgram(InvalidProgramInfo::AlreadyReported(err)).into()
87 }
88}
89
416331ca
XL
90impl<'tcx> From<InterpError<'tcx>> for InterpErrorInfo<'tcx> {
91 fn from(kind: InterpError<'tcx>) -> Self {
3dfed10e
XL
92 let capture_backtrace = tls::with_opt(|tcx| {
93 if let Some(tcx) = tcx {
94 *Lock::borrow(&tcx.sess.ctfe_backtrace)
ba9703b0
XL
95 } else {
96 CtfeBacktrace::Disabled
97 }
98 });
a1dfa0c6 99
ba9703b0
XL
100 let backtrace = match capture_backtrace {
101 CtfeBacktrace::Disabled => None,
f9f354fc 102 CtfeBacktrace::Capture => Some(Box::new(Backtrace::force_capture())),
ba9703b0
XL
103 CtfeBacktrace::Immediate => {
104 // Print it now.
f9f354fc
XL
105 let backtrace = Backtrace::force_capture();
106 print_backtrace(&backtrace);
ba9703b0 107 None
dfeec247 108 }
a1dfa0c6 109 };
ba9703b0 110
dfeec247 111 InterpErrorInfo { kind, backtrace }
ea8adc8c
XL
112 }
113}
114
e1599b0c
XL
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.
416331ca
XL
118pub enum InvalidProgramInfo<'tcx> {
119 /// Resolution can fail if we are in a too generic context.
120 TooGeneric,
121 /// Cannot compute this constant because it depends on another one
122 /// which already produced an error.
123 ReferencedConstant,
29967ef6
XL
124 /// Abort in case errors are already reported.
125 AlreadyReported(ErrorReported),
416331ca
XL
126 /// An error occurred during layout computation.
127 Layout(layout::LayoutError<'tcx>),
ba9703b0
XL
128 /// An invalid transmute happened.
129 TransmuteSizeDiff(Ty<'tcx>, Ty<'tcx>),
416331ca 130}
b7449926 131
f9f354fc 132impl fmt::Display for InvalidProgramInfo<'_> {
416331ca
XL
133 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
134 use InvalidProgramInfo::*;
135 match self {
dfeec247
XL
136 TooGeneric => write!(f, "encountered overly generic constant"),
137 ReferencedConstant => write!(f, "referenced constant has errors"),
29967ef6 138 AlreadyReported(ErrorReported) => {
ba9703b0
XL
139 write!(f, "encountered constants with type errors, stopping evaluation")
140 }
dfeec247 141 Layout(ref err) => write!(f, "{}", err),
ba9703b0
XL
142 TransmuteSizeDiff(from_ty, to_ty) => write!(
143 f,
144 "transmuting `{}` to `{}` is not possible, because these types do not have the same size",
145 from_ty, to_ty
146 ),
416331ca
XL
147 }
148 }
149}
150
f9f354fc 151/// Details of why a pointer had to be in-bounds.
3dfed10e 152#[derive(Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)]
f9f354fc
XL
153pub enum CheckInAllocMsg {
154 MemoryAccessTest,
155 NullPointerTest,
156 PointerArithmeticTest,
157 InboundsTest,
158}
159
160impl 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 {
164 write!(
165 f,
166 "{}",
167 match *self {
168 CheckInAllocMsg::MemoryAccessTest => "memory access",
169 CheckInAllocMsg::NullPointerTest => "NULL pointer test",
170 CheckInAllocMsg::PointerArithmeticTest => "pointer arithmetic",
171 CheckInAllocMsg::InboundsTest => "inbounds test",
172 }
173 )
174 }
175}
176
177/// Details of an access to uninitialized bytes where it is not allowed.
178#[derive(Debug)]
179pub 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,
188}
189
e1599b0c 190/// Error information for when the program caused Undefined Behavior.
f9f354fc 191pub enum UndefinedBehaviorInfo<'tcx> {
416331ca
XL
192 /// Free-form case. Only for errors that are never caught!
193 Ub(String),
416331ca
XL
194 /// Unreachable code was executed.
195 Unreachable,
60c5eb7d 196 /// A slice/array index projection went out-of-bounds.
ba9703b0
XL
197 BoundsCheckFailed {
198 len: u64,
199 index: u64,
200 },
60c5eb7d
XL
201 /// Something was divided by 0 (x / 0).
202 DivisionByZero,
203 /// Something was "remainded" by 0 (x % 0).
204 RemainderByZero,
205 /// Overflowing inbounds pointer arithmetic.
206 PointerArithOverflow,
74b04a01
XL
207 /// Invalid metadata in a wide pointer (using `str` to avoid allocations).
208 InvalidMeta(&'static str),
f9f354fc
XL
209 /// Invalid drop function in vtable.
210 InvalidDropFn(FnSig<'tcx>),
ba9703b0
XL
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.
216 PointerOutOfBounds {
217 ptr: Pointer,
218 msg: CheckInAllocMsg,
219 allocation_size: Size,
220 },
f9f354fc
XL
221 /// Using an integer as a pointer in the wrong way.
222 DanglingIntPointer(u64, CheckInAllocMsg),
ba9703b0
XL
223 /// Used a pointer with bad alignment.
224 AlignmentCheckFailed {
225 required: Align,
226 has: Align,
227 },
ba9703b0
XL
228 /// Writing to read-only memory.
229 WriteToReadOnly(AllocId),
ba9703b0
XL
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
234 /// is the problem.
235 ValidationFailure(String),
236 /// Using a non-boolean `u8` as bool.
237 InvalidBool(u8),
238 /// Using a non-character `u32` as character.
239 InvalidChar(u32),
f035d41b
XL
240 /// The tag of an enum does not encode an actual discriminant.
241 InvalidTag(Scalar),
f9f354fc
XL
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),
ba9703b0 246 /// Using uninitialized data where it is not allowed.
f9f354fc 247 InvalidUninitBytes(Option<Box<UninitBytesAccess>>),
ba9703b0
XL
248 /// Working with a local that is not currently live.
249 DeadLocal,
f9f354fc
XL
250 /// Data size is not equal to target size.
251 ScalarSizeMismatch {
252 target_size: u64,
253 data_size: u64,
254 },
416331ca 255}
48663c56 256
f9f354fc 257impl fmt::Display for UndefinedBehaviorInfo<'_> {
416331ca
XL
258 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
259 use UndefinedBehaviorInfo::*;
260 match self {
ba9703b0 261 Ub(msg) => write!(f, "{}", msg),
dfeec247 262 Unreachable => write!(f, "entering unreachable code"),
f9f354fc
XL
263 BoundsCheckFailed { ref len, ref index } => {
264 write!(f, "indexing out of bounds: the len is {} but the index is {}", len, index)
265 }
dfeec247
XL
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"),
74b04a01 269 InvalidMeta(msg) => write!(f, "invalid metadata in wide pointer: {}", msg),
f9f354fc
XL
270 InvalidDropFn(sig) => write!(
271 f,
272 "invalid drop function signature: got {}, expected exactly one argument which must be a pointer type",
273 sig
274 ),
ba9703b0
XL
275 UnterminatedCString(p) => write!(
276 f,
f9f354fc 277 "reading a null-terminated string starting at {} with no null found before end of allocation",
ba9703b0
XL
278 p,
279 ),
280 PointerUseAfterFree(a) => {
f9f354fc 281 write!(f, "pointer to {} was dereferenced after this allocation got freed", a)
ba9703b0
XL
282 }
283 PointerOutOfBounds { ptr, msg, allocation_size } => write!(
284 f,
285 "{} failed: pointer must be in-bounds at offset {}, \
286 but is outside bounds of {} which has size {}",
287 msg,
288 ptr.offset.bytes(),
289 ptr.alloc_id,
290 allocation_size.bytes()
291 ),
f9f354fc
XL
292 DanglingIntPointer(_, CheckInAllocMsg::NullPointerTest) => {
293 write!(f, "NULL pointer is not allowed for this operation")
294 }
295 DanglingIntPointer(i, msg) => {
296 write!(f, "{} failed: 0x{:x} is not a valid pointer", msg, i)
297 }
ba9703b0
XL
298 AlignmentCheckFailed { required, has } => write!(
299 f,
300 "accessing memory with alignment {}, but alignment {} is required",
301 has.bytes(),
302 required.bytes()
303 ),
f9f354fc
XL
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),
307 InvalidBool(b) => {
308 write!(f, "interpreting an invalid 8-bit value as a bool: 0x{:02x}", b)
309 }
310 InvalidChar(c) => {
311 write!(f, "interpreting an invalid 32-bit value as a char: 0x{:08x}", c)
312 }
f035d41b 313 InvalidTag(val) => write!(f, "enum value has invalid tag: {}", val),
ba9703b0 314 InvalidFunctionPointer(p) => {
f9f354fc 315 write!(f, "using {} as function pointer but it does not point to a function", p)
ba9703b0 316 }
f9f354fc
XL
317 InvalidStr(err) => write!(f, "this string is not valid UTF-8: {}", err),
318 InvalidUninitBytes(Some(access)) => write!(
ba9703b0 319 f,
f9f354fc
XL
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()),
325 access.access_ptr,
326 access.uninit_size.bytes(),
327 pluralize!(access.uninit_size.bytes()),
328 if access.uninit_size.bytes() != 1 { "are" } else { "is" },
329 access.uninit_ptr,
ba9703b0 330 ),
f9f354fc 331 InvalidUninitBytes(None) => write!(
ba9703b0
XL
332 f,
333 "using uninitialized data, but this operation requires initialized memory"
334 ),
335 DeadLocal => write!(f, "accessing a dead local variable"),
f9f354fc
XL
336 ScalarSizeMismatch { target_size, data_size } => write!(
337 f,
338 "scalar size mismatch: expected {} bytes but got {} bytes instead",
339 target_size, data_size
340 ),
416331ca
XL
341 }
342 }
343}
344
e1599b0c
XL
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
f9f354fc 348/// Miri engine, e.g., CTFE does not support dereferencing pointers at integral addresses.
ba9703b0 349pub enum UnsupportedOpInfo {
416331ca
XL
350 /// Free-form case. Only for errors that are never caught!
351 Unsupported(String),
ba9703b0
XL
352 /// Could not find MIR for a function.
353 NoMirFor(DefId),
354 /// Encountered a pointer where we needed raw bytes.
ea8adc8c 355 ReadPointerAsBytes,
f9f354fc
XL
356 //
357 // The variants below are only reachable from CTFE/const prop, miri will never emit them.
358 //
ba9703b0 359 /// Encountered raw bytes where we needed a pointer.
ea8adc8c 360 ReadBytesAsPointer,
f9f354fc
XL
361 /// Accessing thread local statics
362 ThreadLocalStatic(DefId),
3dfed10e
XL
363 /// Accessing an unsupported extern static.
364 ReadExternStatic(DefId),
ea8adc8c
XL
365}
366
f9f354fc 367impl fmt::Display for UnsupportedOpInfo {
a1dfa0c6 368 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
416331ca
XL
369 use UnsupportedOpInfo::*;
370 match self {
dfeec247 371 Unsupported(ref msg) => write!(f, "{}", msg),
3dfed10e 372 ReadExternStatic(did) => write!(f, "cannot read from extern static ({:?})", did),
ba9703b0
XL
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"),
f9f354fc 376 ThreadLocalStatic(did) => write!(f, "cannot access thread local static ({:?})", did),
416331ca
XL
377 }
378 }
379}
380
e1599b0c
XL
381/// Error information for when the program exhausted the resources granted to it
382/// by the interpreter.
416331ca
XL
383pub enum ResourceExhaustionInfo {
384 /// The stack grew too big.
385 StackFrameLimitReached,
ba9703b0
XL
386 /// The program ran for too long.
387 ///
388 /// The exact limit is set by the `const_eval_limit` attribute.
389 StepLimitReached,
416331ca
XL
390}
391
f9f354fc 392impl fmt::Display for ResourceExhaustionInfo {
416331ca
XL
393 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
394 use ResourceExhaustionInfo::*;
395 match self {
dfeec247
XL
396 StackFrameLimitReached => {
397 write!(f, "reached the configured maximum number of stack frames")
398 }
ba9703b0
XL
399 StepLimitReached => {
400 write!(f, "exceeded interpreter step limit (see `#[const_eval_limit]`)")
401 }
416331ca
XL
402 }
403 }
404}
405
ba9703b0
XL
406/// A trait to work around not having trait object upcasting.
407pub trait AsAny: Any {
408 fn as_any(&self) -> &dyn Any;
409}
ba9703b0
XL
410impl<T: Any> AsAny for T {
411 #[inline(always)]
412 fn as_any(&self) -> &dyn Any {
413 self
414 }
415}
416
417/// A trait for machine-specific errors (or other "machine stop" conditions).
f9f354fc 418pub trait MachineStopType: AsAny + fmt::Display + Send {}
ba9703b0
XL
419impl MachineStopType for String {}
420
421impl dyn MachineStopType {
422 #[inline(always)]
423 pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
424 self.as_any().downcast_ref()
425 }
426}
427
f9f354fc
XL
428#[cfg(target_arch = "x86_64")]
429static_assert_size!(InterpError<'_>, 40);
430
416331ca 431pub enum InterpError<'tcx> {
416331ca 432 /// The program caused undefined behavior.
f9f354fc 433 UndefinedBehavior(UndefinedBehaviorInfo<'tcx>),
416331ca
XL
434 /// The program did something the interpreter does not support (some of these *might* be UB
435 /// but the interpreter is not sure).
ba9703b0 436 Unsupported(UnsupportedOpInfo),
60c5eb7d 437 /// The program was invalid (ill-typed, bad MIR, not sufficiently monomorphized, ...).
416331ca
XL
438 InvalidProgram(InvalidProgramInfo<'tcx>),
439 /// The program exhausted the interpreter's resources (stack/heap too big,
60c5eb7d 440 /// execution takes too long, ...).
416331ca 441 ResourceExhaustion(ResourceExhaustionInfo),
60c5eb7d
XL
442 /// Stop execution for a machine-controlled reason. This is never raised by
443 /// the core engine itself.
ba9703b0 444 MachineStop(Box<dyn MachineStopType>),
416331ca
XL
445}
446
447pub type InterpResult<'tcx, T = ()> = Result<T, InterpErrorInfo<'tcx>>;
448
449impl fmt::Display for InterpError<'_> {
450 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f9f354fc
XL
451 use InterpError::*;
452 match *self {
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),
458 }
416331ca
XL
459 }
460}
461
f9f354fc 462// Forward `Debug` to `Display`, so it does not look awful.
416331ca
XL
463impl fmt::Debug for InterpError<'_> {
464 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f9f354fc 465 fmt::Display::fmt(self, f)
74b04a01
XL
466 }
467}
468
469impl 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 {
474 match self {
ba9703b0
XL
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(_))
f9f354fc
XL
479 | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::Ub(_))
480 | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::InvalidUninitBytes(Some(_))) => {
481 true
482 }
74b04a01 483 _ => false,
ea8adc8c
XL
484 }
485 }
486}