]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_middle/src/mir/interpret/error.rs
New upstream version 1.73.0+dfsg1
[rustc.git] / compiler / rustc_middle / src / mir / interpret / error.rs
CommitLineData
064997fb 1use super::{AllocId, AllocRange, ConstAlloc, Pointer, Scalar};
ea8adc8c 2
74b04a01 3use crate::mir::interpret::ConstValue;
49aad941
FG
4use crate::query::TyCtxtAt;
5use crate::ty::{layout, tls, Ty, ValTree};
ea8adc8c 6
ba9703b0 7use rustc_data_structures::sync::Lock;
fe692bf9
FG
8use rustc_errors::{
9 struct_span_err, DiagnosticArgValue, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed,
10 IntoDiagnosticArg,
11};
e1599b0c 12use rustc_macros::HashStable;
ba9703b0 13use rustc_session::CtfeBacktrace;
3dfed10e 14use rustc_span::def_id::DefId;
add651ee
FG
15use rustc_target::abi::{call, Align, Size, VariantIdx, WrappingRange};
16
fe692bf9 17use std::borrow::Cow;
6a06907d 18use std::{any::Any, backtrace::Backtrace, fmt};
e1599b0c 19
3dfed10e 20#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
a1dfa0c6 21pub enum ErrorHandled {
ba9703b0
XL
22 /// Already reported an error for this evaluation, and the compilation is
23 /// *guaranteed* to fail. Warnings/lints *must not* produce `Reported`.
49aad941 24 Reported(ReportedErrorInfo),
a1dfa0c6 25 /// Don't emit an error, the evaluation failed because the MIR was generic
add651ee 26 /// and the args didn't fully monomorphize it.
a1dfa0c6
XL
27 TooGeneric,
28}
29
5e7ed085 30impl From<ErrorGuaranteed> for ErrorHandled {
49aad941
FG
31 #[inline]
32 fn from(error: ErrorGuaranteed) -> ErrorHandled {
33 ErrorHandled::Reported(error.into())
34 }
35}
36
37#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
38pub struct ReportedErrorInfo {
39 error: ErrorGuaranteed,
40 is_tainted_by_errors: bool,
41}
42
43impl ReportedErrorInfo {
44 #[inline]
45 pub fn tainted_by_errors(error: ErrorGuaranteed) -> ReportedErrorInfo {
46 ReportedErrorInfo { is_tainted_by_errors: true, error }
47 }
48
49 /// Returns true if evaluation failed because MIR was tainted by errors.
50 #[inline]
51 pub fn is_tainted_by_errors(self) -> bool {
52 self.is_tainted_by_errors
53 }
54}
55
56impl From<ErrorGuaranteed> for ReportedErrorInfo {
57 #[inline]
58 fn from(error: ErrorGuaranteed) -> ReportedErrorInfo {
59 ReportedErrorInfo { is_tainted_by_errors: false, error }
60 }
61}
62
63impl Into<ErrorGuaranteed> for ReportedErrorInfo {
64 #[inline]
65 fn into(self) -> ErrorGuaranteed {
66 self.error
1b1a35ee
XL
67 }
68}
69
add651ee 70TrivialTypeTraversalAndLiftImpls! { ErrorHandled }
dc9dc135 71
1b1a35ee
XL
72pub type EvalToAllocationRawResult<'tcx> = Result<ConstAlloc<'tcx>, ErrorHandled>;
73pub type EvalToConstValueResult<'tcx> = Result<ConstValue<'tcx>, ErrorHandled>;
923072b8 74pub type EvalToValTreeResult<'tcx> = Result<Option<ValTree<'tcx>>, ErrorHandled>;
8faf50e0 75
5e7ed085
FG
76pub fn struct_error<'tcx>(
77 tcx: TyCtxtAt<'tcx>,
78 msg: &str,
79) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
8faf50e0
XL
80 struct_span_err!(tcx.sess, tcx.span, E0080, "{}", msg)
81}
82
6a06907d
XL
83#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
84static_assert_size!(InterpErrorInfo<'_>, 8);
85
dc9dc135 86/// Packages the kind of error we got from the const code interpreter
60c5eb7d 87/// up with a Rust-level backtrace of where the error occurred.
cdc7bbd5 88/// These should always be constructed by calling `.into()` on
94222f64 89/// an `InterpError`. In `rustc_mir::interpret`, we have `throw_err_*`
416331ca 90/// macros for this.
60c5eb7d 91#[derive(Debug)]
6a06907d
XL
92pub struct InterpErrorInfo<'tcx>(Box<InterpErrorInfoInner<'tcx>>);
93
94#[derive(Debug)]
95struct InterpErrorInfoInner<'tcx> {
96 kind: InterpError<'tcx>,
fe692bf9
FG
97 backtrace: InterpErrorBacktrace,
98}
99
100#[derive(Debug)]
101pub struct InterpErrorBacktrace {
dc9dc135 102 backtrace: Option<Box<Backtrace>>,
a1dfa0c6
XL
103}
104
fe692bf9
FG
105impl InterpErrorBacktrace {
106 pub fn new() -> InterpErrorBacktrace {
107 let capture_backtrace = tls::with_opt(|tcx| {
108 if let Some(tcx) = tcx {
109 *Lock::borrow(&tcx.sess.ctfe_backtrace)
110 } else {
111 CtfeBacktrace::Disabled
112 }
113 });
114
115 let backtrace = match capture_backtrace {
116 CtfeBacktrace::Disabled => None,
117 CtfeBacktrace::Capture => Some(Box::new(Backtrace::force_capture())),
118 CtfeBacktrace::Immediate => {
119 // Print it now.
120 let backtrace = Backtrace::force_capture();
121 print_backtrace(&backtrace);
122 None
123 }
124 };
125
126 InterpErrorBacktrace { backtrace }
416331ca 127 }
416331ca 128
f9f354fc 129 pub fn print_backtrace(&self) {
fe692bf9 130 if let Some(backtrace) = self.backtrace.as_ref() {
f9f354fc 131 print_backtrace(backtrace);
a1dfa0c6
XL
132 }
133 }
fe692bf9
FG
134}
135
136impl<'tcx> InterpErrorInfo<'tcx> {
fe692bf9
FG
137 pub fn into_parts(self) -> (InterpError<'tcx>, InterpErrorBacktrace) {
138 let InterpErrorInfo(box InterpErrorInfoInner { kind, backtrace }) = self;
139 (kind, backtrace)
140 }
6a06907d
XL
141
142 pub fn into_kind(self) -> InterpError<'tcx> {
143 let InterpErrorInfo(box InterpErrorInfoInner { kind, .. }) = self;
144 kind
145 }
146
147 #[inline]
148 pub fn kind(&self) -> &InterpError<'tcx> {
149 &self.0.kind
150 }
a1dfa0c6
XL
151}
152
f9f354fc 153fn print_backtrace(backtrace: &Backtrace) {
add651ee 154 eprintln!("\n\nAn error occurred in the MIR interpreter:\n{backtrace}");
ea8adc8c
XL
155}
156
5e7ed085
FG
157impl From<ErrorGuaranteed> for InterpErrorInfo<'_> {
158 fn from(err: ErrorGuaranteed) -> Self {
49aad941 159 InterpError::InvalidProgram(InvalidProgramInfo::AlreadyReported(err.into())).into()
29967ef6
XL
160 }
161}
162
416331ca
XL
163impl<'tcx> From<InterpError<'tcx>> for InterpErrorInfo<'tcx> {
164 fn from(kind: InterpError<'tcx>) -> Self {
fe692bf9
FG
165 InterpErrorInfo(Box::new(InterpErrorInfoInner {
166 kind,
167 backtrace: InterpErrorBacktrace::new(),
168 }))
ea8adc8c
XL
169 }
170}
171
e1599b0c
XL
172/// Error information for when the program we executed turned out not to actually be a valid
173/// program. This cannot happen in stand-alone Miri, but it can happen during CTFE/ConstProp
174/// where we work on generic code or execution does not have all information available.
fe692bf9 175#[derive(Debug)]
416331ca
XL
176pub enum InvalidProgramInfo<'tcx> {
177 /// Resolution can fail if we are in a too generic context.
178 TooGeneric,
29967ef6 179 /// Abort in case errors are already reported.
49aad941 180 AlreadyReported(ReportedErrorInfo),
416331ca
XL
181 /// An error occurred during layout computation.
182 Layout(layout::LayoutError<'tcx>),
a2a8927a
XL
183 /// An error occurred during FnAbi computation: the passed --target lacks FFI support
184 /// (which unfortunately typeck does not reject).
185 /// Not using `FnAbiError` as that contains a nested `LayoutError`.
186 FnAbiAdjustForForeignAbi(call::AdjustForForeignAbiError),
add651ee
FG
187 /// We are runnning into a nonsense situation due to ConstProp violating our invariants.
188 ConstPropNonsense,
416331ca 189}
b7449926 190
f9f354fc 191/// Details of why a pointer had to be in-bounds.
3dfed10e 192#[derive(Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)]
f9f354fc 193pub enum CheckInAllocMsg {
136023e0
XL
194 /// We are dereferencing a pointer (i.e., creating a place).
195 DerefTest,
17df50a5 196 /// We are access memory.
f9f354fc 197 MemoryAccessTest,
17df50a5 198 /// We are doing pointer arithmetic.
f9f354fc 199 PointerArithmeticTest,
5e7ed085
FG
200 /// We are doing pointer offset_from.
201 OffsetFromTest,
17df50a5 202 /// None of the above -- generic/unspecific inbounds test.
f9f354fc
XL
203 InboundsTest,
204}
205
fe692bf9
FG
206#[derive(Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)]
207pub enum InvalidMetaKind {
208 /// Size of a `[T]` is too big
209 SliceTooBig,
210 /// Size of a DST is too big
211 TooBig,
212}
213
214impl IntoDiagnosticArg for InvalidMetaKind {
215 fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
216 DiagnosticArgValue::Str(Cow::Borrowed(match self {
217 InvalidMetaKind::SliceTooBig => "slice_too_big",
218 InvalidMetaKind::TooBig => "too_big",
219 }))
f9f354fc
XL
220 }
221}
222
add651ee 223/// Details of an access to uninitialized bytes / bad pointer bytes where it is not allowed.
fe692bf9 224#[derive(Debug, Clone, Copy)]
add651ee 225pub struct BadBytesAccess {
064997fb
FG
226 /// Range of the original memory access.
227 pub access: AllocRange,
add651ee
FG
228 /// Range of the bad memory that was encountered. (Might not be maximal.)
229 pub bad: AllocRange,
f9f354fc
XL
230}
231
04454e1e
FG
232/// Information about a size mismatch.
233#[derive(Debug)]
234pub struct ScalarSizeMismatch {
235 pub target_size: u64,
236 pub data_size: u64,
237}
238
fe692bf9
FG
239macro_rules! impl_into_diagnostic_arg_through_debug {
240 ($($ty:ty),*$(,)?) => {$(
241 impl IntoDiagnosticArg for $ty {
242 fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
243 DiagnosticArgValue::Str(Cow::Owned(format!("{self:?}")))
244 }
245 }
246 )*}
247}
248
249// These types have nice `Debug` output so we can just use them in diagnostics.
250impl_into_diagnostic_arg_through_debug! {
251 AllocId,
252 Pointer,
253 AllocRange,
254}
255
e1599b0c 256/// Error information for when the program caused Undefined Behavior.
fe692bf9
FG
257#[derive(Debug)]
258pub enum UndefinedBehaviorInfo<'a> {
259 /// Free-form case. Only for errors that are never caught! Used by miri
416331ca 260 Ub(String),
416331ca
XL
261 /// Unreachable code was executed.
262 Unreachable,
60c5eb7d 263 /// A slice/array index projection went out-of-bounds.
fe692bf9 264 BoundsCheckFailed { len: u64, index: u64 },
60c5eb7d
XL
265 /// Something was divided by 0 (x / 0).
266 DivisionByZero,
267 /// Something was "remainded" by 0 (x % 0).
268 RemainderByZero,
5e7ed085
FG
269 /// Signed division overflowed (INT_MIN / -1).
270 DivisionOverflow,
271 /// Signed remainder overflowed (INT_MIN % -1).
272 RemainderOverflow,
60c5eb7d
XL
273 /// Overflowing inbounds pointer arithmetic.
274 PointerArithOverflow,
fe692bf9
FG
275 /// Invalid metadata in a wide pointer
276 InvalidMeta(InvalidMetaKind),
ba9703b0
XL
277 /// Reading a C string that does not end within its allocation.
278 UnterminatedCString(Pointer),
add651ee
FG
279 /// Using a pointer after it got freed.
280 PointerUseAfterFree(AllocId, CheckInAllocMsg),
ba9703b0 281 /// Used a pointer outside the bounds it is valid for.
136023e0 282 /// (If `ptr_size > 0`, determines the size of the memory range that was expected to be in-bounds.)
ba9703b0 283 PointerOutOfBounds {
136023e0
XL
284 alloc_id: AllocId,
285 alloc_size: Size,
286 ptr_offset: i64,
287 ptr_size: Size,
ba9703b0 288 msg: CheckInAllocMsg,
ba9703b0 289 },
f9f354fc
XL
290 /// Using an integer as a pointer in the wrong way.
291 DanglingIntPointer(u64, CheckInAllocMsg),
ba9703b0 292 /// Used a pointer with bad alignment.
fe692bf9 293 AlignmentCheckFailed { required: Align, has: Align },
ba9703b0
XL
294 /// Writing to read-only memory.
295 WriteToReadOnly(AllocId),
fe692bf9 296 /// Trying to access the data behind a function pointer.
ba9703b0 297 DerefFunctionPointer(AllocId),
fe692bf9 298 /// Trying to access the data behind a vtable pointer.
064997fb 299 DerefVTablePointer(AllocId),
ba9703b0
XL
300 /// Using a non-boolean `u8` as bool.
301 InvalidBool(u8),
302 /// Using a non-character `u32` as character.
303 InvalidChar(u32),
f035d41b
XL
304 /// The tag of an enum does not encode an actual discriminant.
305 InvalidTag(Scalar),
f9f354fc
XL
306 /// Using a pointer-not-to-a-function as function pointer.
307 InvalidFunctionPointer(Pointer),
064997fb
FG
308 /// Using a pointer-not-to-a-vtable as vtable pointer.
309 InvalidVTablePointer(Pointer),
f9f354fc
XL
310 /// Using a string that is not valid UTF-8,
311 InvalidStr(std::str::Utf8Error),
ba9703b0 312 /// Using uninitialized data where it is not allowed.
add651ee 313 InvalidUninitBytes(Option<(AllocId, BadBytesAccess)>),
ba9703b0
XL
314 /// Working with a local that is not currently live.
315 DeadLocal,
f9f354fc 316 /// Data size is not equal to target size.
04454e1e 317 ScalarSizeMismatch(ScalarSizeMismatch),
c295e0f8 318 /// A discriminant of an uninhabited enum variant is written.
add651ee
FG
319 UninhabitedEnumVariantWritten(VariantIdx),
320 /// An uninhabited enum variant is projected.
321 UninhabitedEnumVariantRead(VariantIdx),
fe692bf9 322 /// Validation error.
add651ee 323 ValidationError(ValidationErrorInfo<'a>),
fe692bf9
FG
324 // FIXME(fee1-dead) these should all be actual variants of the enum instead of dynamically
325 // dispatched
326 /// A custom (free-form) error, created by `err_ub_custom!`.
327 Custom(crate::error::CustomSubdiagnostic<'a>),
328}
329
330#[derive(Debug, Clone, Copy)]
331pub enum PointerKind {
332 Ref,
333 Box,
334}
335
336impl IntoDiagnosticArg for PointerKind {
337 fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
338 DiagnosticArgValue::Str(
339 match self {
340 Self::Ref => "ref",
341 Self::Box => "box",
342 }
343 .into(),
344 )
345 }
416331ca 346}
48663c56 347
fe692bf9
FG
348#[derive(Debug)]
349pub struct ValidationErrorInfo<'tcx> {
350 pub path: Option<String>,
351 pub kind: ValidationErrorKind<'tcx>,
352}
353
354#[derive(Debug)]
355pub enum ExpectedKind {
356 Reference,
357 Box,
358 RawPtr,
359 InitScalar,
360 Bool,
361 Char,
362 Float,
363 Int,
364 FnPtr,
add651ee
FG
365 EnumTag,
366 Str,
fe692bf9
FG
367}
368
369impl From<PointerKind> for ExpectedKind {
370 fn from(x: PointerKind) -> ExpectedKind {
371 match x {
372 PointerKind::Box => ExpectedKind::Box,
373 PointerKind::Ref => ExpectedKind::Reference,
416331ca
XL
374 }
375 }
376}
377
fe692bf9
FG
378#[derive(Debug)]
379pub enum ValidationErrorKind<'tcx> {
add651ee
FG
380 PointerAsInt { expected: ExpectedKind },
381 PartialPointer,
fe692bf9
FG
382 PtrToUninhabited { ptr_kind: PointerKind, ty: Ty<'tcx> },
383 PtrToStatic { ptr_kind: PointerKind },
384 PtrToMut { ptr_kind: PointerKind },
fe692bf9
FG
385 MutableRefInConst,
386 NullFnPtr,
387 NeverVal,
388 NullablePtrOutOfRange { range: WrappingRange, max_value: u128 },
389 PtrOutOfRange { range: WrappingRange, max_value: u128 },
390 OutOfRange { value: String, range: WrappingRange, max_value: u128 },
391 UnsafeCell,
392 UninhabitedVal { ty: Ty<'tcx> },
393 InvalidEnumTag { value: String },
add651ee 394 UninhabitedEnumVariant,
fe692bf9 395 Uninit { expected: ExpectedKind },
fe692bf9
FG
396 InvalidVTablePtr { value: String },
397 InvalidMetaSliceTooLarge { ptr_kind: PointerKind },
398 InvalidMetaTooLarge { ptr_kind: PointerKind },
399 UnalignedPtr { ptr_kind: PointerKind, required_bytes: u64, found_bytes: u64 },
400 NullPtr { ptr_kind: PointerKind },
401 DanglingPtrNoProvenance { ptr_kind: PointerKind, pointer: String },
402 DanglingPtrOutOfBounds { ptr_kind: PointerKind },
403 DanglingPtrUseAfterFree { ptr_kind: PointerKind },
404 InvalidBool { value: String },
405 InvalidChar { value: String },
406 InvalidFnPtr { value: String },
407}
408
e1599b0c
XL
409/// Error information for when the program did something that might (or might not) be correct
410/// to do according to the Rust spec, but due to limitations in the interpreter, the
411/// operation could not be carried out. These limitations can differ between CTFE and the
f9f354fc 412/// Miri engine, e.g., CTFE does not support dereferencing pointers at integral addresses.
fe692bf9 413#[derive(Debug)]
ba9703b0 414pub enum UnsupportedOpInfo {
416331ca 415 /// Free-form case. Only for errors that are never caught!
fe692bf9 416 // FIXME still use translatable diagnostics
416331ca 417 Unsupported(String),
f9f354fc
XL
418 //
419 // The variants below are only reachable from CTFE/const prop, miri will never emit them.
420 //
487cf647
FG
421 /// Overwriting parts of a pointer; without knowing absolute addresses, the resulting state
422 /// cannot be represented by the CTFE interpreter.
add651ee
FG
423 OverwritePartialPointer(Pointer<AllocId>),
424 /// Attempting to read or copy parts of a pointer to somewhere else; without knowing absolute
487cf647 425 /// addresses, the resulting state cannot be represented by the CTFE interpreter.
add651ee
FG
426 ReadPartialPointer(Pointer<AllocId>),
427 /// Encountered a pointer where we needed an integer.
428 ReadPointerAsInt(Option<(AllocId, BadBytesAccess)>),
f9f354fc
XL
429 /// Accessing thread local statics
430 ThreadLocalStatic(DefId),
3dfed10e
XL
431 /// Accessing an unsupported extern static.
432 ReadExternStatic(DefId),
ea8adc8c
XL
433}
434
e1599b0c
XL
435/// Error information for when the program exhausted the resources granted to it
436/// by the interpreter.
fe692bf9 437#[derive(Debug)]
416331ca
XL
438pub enum ResourceExhaustionInfo {
439 /// The stack grew too big.
440 StackFrameLimitReached,
9ffffee4 441 /// There is not enough memory (on the host) to perform an allocation.
136023e0 442 MemoryExhausted,
9ffffee4
FG
443 /// The address space (of the target) is full.
444 AddressSpaceFull,
416331ca
XL
445}
446
ba9703b0 447/// A trait for machine-specific errors (or other "machine stop" conditions).
fe692bf9
FG
448pub trait MachineStopType: Any + fmt::Debug + Send {
449 /// The diagnostic message for this error
450 fn diagnostic_message(&self) -> DiagnosticMessage;
451 /// Add diagnostic arguments by passing name and value pairs to `adder`, which are passed to
452 /// fluent for formatting the translated diagnostic message.
453 fn add_args(
454 self: Box<Self>,
455 adder: &mut dyn FnMut(Cow<'static, str>, DiagnosticArgValue<'static>),
456 );
457}
ba9703b0
XL
458
459impl dyn MachineStopType {
460 #[inline(always)]
461 pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
fe692bf9
FG
462 let x: &dyn Any = self;
463 x.downcast_ref()
ba9703b0
XL
464 }
465}
466
fe692bf9 467#[derive(Debug)]
416331ca 468pub enum InterpError<'tcx> {
416331ca 469 /// The program caused undefined behavior.
fe692bf9 470 UndefinedBehavior(UndefinedBehaviorInfo<'tcx>),
416331ca
XL
471 /// The program did something the interpreter does not support (some of these *might* be UB
472 /// but the interpreter is not sure).
ba9703b0 473 Unsupported(UnsupportedOpInfo),
60c5eb7d 474 /// The program was invalid (ill-typed, bad MIR, not sufficiently monomorphized, ...).
416331ca
XL
475 InvalidProgram(InvalidProgramInfo<'tcx>),
476 /// The program exhausted the interpreter's resources (stack/heap too big,
60c5eb7d 477 /// execution takes too long, ...).
416331ca 478 ResourceExhaustion(ResourceExhaustionInfo),
60c5eb7d
XL
479 /// Stop execution for a machine-controlled reason. This is never raised by
480 /// the core engine itself.
ba9703b0 481 MachineStop(Box<dyn MachineStopType>),
416331ca
XL
482}
483
484pub type InterpResult<'tcx, T = ()> = Result<T, InterpErrorInfo<'tcx>>;
485
74b04a01 486impl InterpError<'_> {
136023e0 487 /// Some errors do string formatting even if the error is never printed.
6a06907d
XL
488 /// To avoid performance issues, there are places where we want to be sure to never raise these formatting errors,
489 /// so this method lets us detect them and `bug!` on unexpected errors.
490 pub fn formatted_string(&self) -> bool {
3c0e092e
XL
491 matches!(
492 self,
ba9703b0 493 InterpError::Unsupported(UnsupportedOpInfo::Unsupported(_))
add651ee 494 | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::ValidationError { .. })
3c0e092e
XL
495 | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::Ub(_))
496 )
ea8adc8c
XL
497 }
498}