]> git.proxmox.com Git - rustc.git/blob - src/librustc/mir/interpret/error.rs
New upstream version 1.35.0+dfsg1
[rustc.git] / src / librustc / mir / interpret / error.rs
1 use std::{fmt, env};
2
3 use crate::hir;
4 use crate::hir::map::definitions::DefPathData;
5 use crate::mir;
6 use crate::ty::{self, Ty, layout};
7 use crate::ty::layout::{Size, Align, LayoutError};
8 use rustc_target::spec::abi::Abi;
9 use rustc_macros::HashStable;
10
11 use super::{RawConst, Pointer, InboundsCheck, ScalarMaybeUndef};
12
13 use backtrace::Backtrace;
14
15 use crate::ty::query::TyCtxtAt;
16 use errors::DiagnosticBuilder;
17
18 use syntax_pos::{Pos, Span};
19 use syntax::symbol::Symbol;
20
21 #[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable)]
22 pub enum ErrorHandled {
23 /// Already reported a lint or an error for this evaluation.
24 Reported,
25 /// Don't emit an error, the evaluation failed because the MIR was generic
26 /// and the substs didn't fully monomorphize it.
27 TooGeneric,
28 }
29
30 impl ErrorHandled {
31 pub fn assert_reported(self) {
32 match self {
33 ErrorHandled::Reported => {},
34 ErrorHandled::TooGeneric => bug!("MIR interpretation failed without reporting an error \
35 even though it was fully monomorphized"),
36 }
37 }
38 }
39
40 pub type ConstEvalRawResult<'tcx> = Result<RawConst<'tcx>, ErrorHandled>;
41 pub type ConstEvalResult<'tcx> = Result<ty::Const<'tcx>, ErrorHandled>;
42
43 #[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
44 pub struct ConstEvalErr<'tcx> {
45 pub span: Span,
46 pub error: crate::mir::interpret::InterpError<'tcx, u64>,
47 pub stacktrace: Vec<FrameInfo<'tcx>>,
48 }
49
50 #[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)]
51 pub struct FrameInfo<'tcx> {
52 pub call_site: Span, // this span is in the caller!
53 pub instance: ty::Instance<'tcx>,
54 pub lint_root: Option<hir::HirId>,
55 }
56
57 impl<'tcx> fmt::Display for FrameInfo<'tcx> {
58 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
59 ty::tls::with(|tcx| {
60 if tcx.def_key(self.instance.def_id()).disambiguated_data.data
61 == DefPathData::ClosureExpr
62 {
63 write!(f, "inside call to closure")?;
64 } else {
65 write!(f, "inside call to `{}`", self.instance)?;
66 }
67 if !self.call_site.is_dummy() {
68 let lo = tcx.sess.source_map().lookup_char_pos_adj(self.call_site.lo());
69 write!(f, " at {}:{}:{}", lo.filename, lo.line, lo.col.to_usize() + 1)?;
70 }
71 Ok(())
72 })
73 }
74 }
75
76 impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
77 pub fn struct_error(&self,
78 tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
79 message: &str)
80 -> Result<DiagnosticBuilder<'tcx>, ErrorHandled>
81 {
82 self.struct_generic(tcx, message, None)
83 }
84
85 pub fn report_as_error(&self,
86 tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
87 message: &str
88 ) -> ErrorHandled {
89 let err = self.struct_error(tcx, message);
90 match err {
91 Ok(mut err) => {
92 err.emit();
93 ErrorHandled::Reported
94 },
95 Err(err) => err,
96 }
97 }
98
99 pub fn report_as_lint(&self,
100 tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
101 message: &str,
102 lint_root: hir::HirId,
103 span: Option<Span>,
104 ) -> ErrorHandled {
105 let lint = self.struct_generic(
106 tcx,
107 message,
108 Some(lint_root),
109 );
110 match lint {
111 Ok(mut lint) => {
112 if let Some(span) = span {
113 let primary_spans = lint.span.primary_spans().to_vec();
114 // point at the actual error as the primary span
115 lint.replace_span_with(span);
116 // point to the `const` statement as a secondary span
117 // they don't have any label
118 for sp in primary_spans {
119 if sp != span {
120 lint.span_label(sp, "");
121 }
122 }
123 }
124 lint.emit();
125 ErrorHandled::Reported
126 },
127 Err(err) => err,
128 }
129 }
130
131 fn struct_generic(
132 &self,
133 tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
134 message: &str,
135 lint_root: Option<hir::HirId>,
136 ) -> Result<DiagnosticBuilder<'tcx>, ErrorHandled> {
137 match self.error {
138 InterpError::Layout(LayoutError::Unknown(_)) |
139 InterpError::TooGeneric => return Err(ErrorHandled::TooGeneric),
140 InterpError::Layout(LayoutError::SizeOverflow(_)) |
141 InterpError::TypeckError => return Err(ErrorHandled::Reported),
142 _ => {},
143 }
144 trace!("reporting const eval failure at {:?}", self.span);
145 let mut err = if let Some(lint_root) = lint_root {
146 let hir_id = self.stacktrace
147 .iter()
148 .rev()
149 .filter_map(|frame| frame.lint_root)
150 .next()
151 .unwrap_or(lint_root);
152 tcx.struct_span_lint_hir(
153 crate::rustc::lint::builtin::CONST_ERR,
154 hir_id,
155 tcx.span,
156 message,
157 )
158 } else {
159 struct_error(tcx, message)
160 };
161 err.span_label(self.span, self.error.to_string());
162 // Skip the last, which is just the environment of the constant. The stacktrace
163 // is sometimes empty because we create "fake" eval contexts in CTFE to do work
164 // on constant values.
165 if self.stacktrace.len() > 0 {
166 for frame_info in &self.stacktrace[..self.stacktrace.len()-1] {
167 err.span_label(frame_info.call_site, frame_info.to_string());
168 }
169 }
170 Ok(err)
171 }
172 }
173
174 pub fn struct_error<'a, 'gcx, 'tcx>(
175 tcx: TyCtxtAt<'a, 'gcx, 'tcx>,
176 msg: &str,
177 ) -> DiagnosticBuilder<'tcx> {
178 struct_span_err!(tcx.sess, tcx.span, E0080, "{}", msg)
179 }
180
181 #[derive(Debug, Clone)]
182 pub struct EvalError<'tcx> {
183 pub kind: InterpError<'tcx, u64>,
184 pub backtrace: Option<Box<Backtrace>>,
185 }
186
187 impl<'tcx> EvalError<'tcx> {
188 pub fn print_backtrace(&mut self) {
189 if let Some(ref mut backtrace) = self.backtrace {
190 print_backtrace(&mut *backtrace);
191 }
192 }
193 }
194
195 fn print_backtrace(backtrace: &mut Backtrace) {
196 backtrace.resolve();
197 eprintln!("\n\nAn error occurred in miri:\n{:?}", backtrace);
198 }
199
200 impl<'tcx> From<InterpError<'tcx, u64>> for EvalError<'tcx> {
201 fn from(kind: InterpError<'tcx, u64>) -> Self {
202 let backtrace = match env::var("RUST_CTFE_BACKTRACE") {
203 // matching RUST_BACKTRACE, we treat "0" the same as "not present".
204 Ok(ref val) if val != "0" => {
205 let mut backtrace = Backtrace::new_unresolved();
206
207 if val == "immediate" {
208 // Print it now
209 print_backtrace(&mut backtrace);
210 None
211 } else {
212 Some(Box::new(backtrace))
213 }
214 },
215 _ => None,
216 };
217 EvalError {
218 kind,
219 backtrace,
220 }
221 }
222 }
223
224 pub type AssertMessage<'tcx> = InterpError<'tcx, mir::Operand<'tcx>>;
225
226 #[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]
227 pub enum InterpError<'tcx, O> {
228 /// This variant is used by machines to signal their own errors that do not
229 /// match an existing variant.
230 MachineError(String),
231
232 FunctionAbiMismatch(Abi, Abi),
233 FunctionArgMismatch(Ty<'tcx>, Ty<'tcx>),
234 FunctionRetMismatch(Ty<'tcx>, Ty<'tcx>),
235 FunctionArgCountMismatch,
236 NoMirFor(String),
237 UnterminatedCString(Pointer),
238 DanglingPointerDeref,
239 DoubleFree,
240 InvalidMemoryAccess,
241 InvalidFunctionPointer,
242 InvalidBool,
243 InvalidDiscriminant(ScalarMaybeUndef),
244 PointerOutOfBounds {
245 ptr: Pointer,
246 check: InboundsCheck,
247 allocation_size: Size,
248 },
249 InvalidNullPointerUsage,
250 ReadPointerAsBytes,
251 ReadBytesAsPointer,
252 ReadForeignStatic,
253 InvalidPointerMath,
254 ReadUndefBytes(Size),
255 DeadLocal,
256 InvalidBoolOp(mir::BinOp),
257 Unimplemented(String),
258 DerefFunctionPointer,
259 ExecuteMemory,
260 BoundsCheck { len: O, index: O },
261 Overflow(mir::BinOp),
262 OverflowNeg,
263 DivisionByZero,
264 RemainderByZero,
265 Intrinsic(String),
266 InvalidChar(u128),
267 StackFrameLimitReached,
268 OutOfTls,
269 TlsOutOfBounds,
270 AbiViolation(String),
271 AlignmentCheckFailed {
272 required: Align,
273 has: Align,
274 },
275 ValidationFailure(String),
276 CalledClosureAsFunction,
277 VtableForArgumentlessMethod,
278 ModifiedConstantMemory,
279 ModifiedStatic,
280 AssumptionNotHeld,
281 InlineAsm,
282 TypeNotPrimitive(Ty<'tcx>),
283 ReallocatedWrongMemoryKind(String, String),
284 DeallocatedWrongMemoryKind(String, String),
285 ReallocateNonBasePtr,
286 DeallocateNonBasePtr,
287 IncorrectAllocationInformation(Size, Size, Align, Align),
288 Layout(layout::LayoutError<'tcx>),
289 HeapAllocZeroBytes,
290 HeapAllocNonPowerOfTwoAlignment(u64),
291 Unreachable,
292 Panic {
293 msg: Symbol,
294 line: u32,
295 col: u32,
296 file: Symbol,
297 },
298 ReadFromReturnPointer,
299 PathNotFound(Vec<String>),
300 UnimplementedTraitSelection,
301 /// Abort in case type errors are reached
302 TypeckError,
303 /// Resolution can fail if we are in a too generic context
304 TooGeneric,
305 /// Cannot compute this constant because it depends on another one
306 /// which already produced an error
307 ReferencedConstant,
308 GeneratorResumedAfterReturn,
309 GeneratorResumedAfterPanic,
310 InfiniteLoop,
311 }
312
313 pub type EvalResult<'tcx, T = ()> = Result<T, EvalError<'tcx>>;
314
315 impl<'tcx, O> InterpError<'tcx, O> {
316 pub fn description(&self) -> &str {
317 use self::InterpError::*;
318 match *self {
319 MachineError(ref inner) => inner,
320 FunctionAbiMismatch(..) | FunctionArgMismatch(..) | FunctionRetMismatch(..)
321 | FunctionArgCountMismatch =>
322 "tried to call a function through a function pointer of incompatible type",
323 InvalidMemoryAccess =>
324 "tried to access memory through an invalid pointer",
325 DanglingPointerDeref =>
326 "dangling pointer was dereferenced",
327 DoubleFree =>
328 "tried to deallocate dangling pointer",
329 InvalidFunctionPointer =>
330 "tried to use a function pointer after offsetting it",
331 InvalidBool =>
332 "invalid boolean value read",
333 InvalidDiscriminant(..) =>
334 "invalid enum discriminant value read",
335 PointerOutOfBounds { .. } =>
336 "pointer offset outside bounds of allocation",
337 InvalidNullPointerUsage =>
338 "invalid use of NULL pointer",
339 ValidationFailure(..) =>
340 "type validation failed",
341 ReadPointerAsBytes =>
342 "a raw memory access tried to access part of a pointer value as raw bytes",
343 ReadBytesAsPointer =>
344 "a memory access tried to interpret some bytes as a pointer",
345 ReadForeignStatic =>
346 "tried to read from foreign (extern) static",
347 InvalidPointerMath =>
348 "attempted to do invalid arithmetic on pointers that would leak base addresses, \
349 e.g., comparing pointers into different allocations",
350 ReadUndefBytes(_) =>
351 "attempted to read undefined bytes",
352 DeadLocal =>
353 "tried to access a dead local variable",
354 InvalidBoolOp(_) =>
355 "invalid boolean operation",
356 Unimplemented(ref msg) => msg,
357 DerefFunctionPointer =>
358 "tried to dereference a function pointer",
359 ExecuteMemory =>
360 "tried to treat a memory pointer as a function pointer",
361 BoundsCheck{..} =>
362 "array index out of bounds",
363 Intrinsic(..) =>
364 "intrinsic failed",
365 NoMirFor(..) =>
366 "mir not found",
367 InvalidChar(..) =>
368 "tried to interpret an invalid 32-bit value as a char",
369 StackFrameLimitReached =>
370 "reached the configured maximum number of stack frames",
371 OutOfTls =>
372 "reached the maximum number of representable TLS keys",
373 TlsOutOfBounds =>
374 "accessed an invalid (unallocated) TLS key",
375 AbiViolation(ref msg) => msg,
376 AlignmentCheckFailed{..} =>
377 "tried to execute a misaligned read or write",
378 CalledClosureAsFunction =>
379 "tried to call a closure through a function pointer",
380 VtableForArgumentlessMethod =>
381 "tried to call a vtable function without arguments",
382 ModifiedConstantMemory =>
383 "tried to modify constant memory",
384 ModifiedStatic =>
385 "tried to modify a static's initial value from another static's initializer",
386 AssumptionNotHeld =>
387 "`assume` argument was false",
388 InlineAsm =>
389 "miri does not support inline assembly",
390 TypeNotPrimitive(_) =>
391 "expected primitive type, got nonprimitive",
392 ReallocatedWrongMemoryKind(_, _) =>
393 "tried to reallocate memory from one kind to another",
394 DeallocatedWrongMemoryKind(_, _) =>
395 "tried to deallocate memory of the wrong kind",
396 ReallocateNonBasePtr =>
397 "tried to reallocate with a pointer not to the beginning of an existing object",
398 DeallocateNonBasePtr =>
399 "tried to deallocate with a pointer not to the beginning of an existing object",
400 IncorrectAllocationInformation(..) =>
401 "tried to deallocate or reallocate using incorrect alignment or size",
402 Layout(_) =>
403 "rustc layout computation failed",
404 UnterminatedCString(_) =>
405 "attempted to get length of a null terminated string, but no null found before end \
406 of allocation",
407 HeapAllocZeroBytes =>
408 "tried to re-, de- or allocate zero bytes on the heap",
409 HeapAllocNonPowerOfTwoAlignment(_) =>
410 "tried to re-, de-, or allocate heap memory with alignment that is not a power of \
411 two",
412 Unreachable =>
413 "entered unreachable code",
414 Panic { .. } =>
415 "the evaluated program panicked",
416 ReadFromReturnPointer =>
417 "tried to read from the return pointer",
418 PathNotFound(_) =>
419 "a path could not be resolved, maybe the crate is not loaded",
420 UnimplementedTraitSelection =>
421 "there were unresolved type arguments during trait selection",
422 TypeckError =>
423 "encountered constants with type errors, stopping evaluation",
424 TooGeneric =>
425 "encountered overly generic constant",
426 ReferencedConstant =>
427 "referenced constant has errors",
428 Overflow(mir::BinOp::Add) => "attempt to add with overflow",
429 Overflow(mir::BinOp::Sub) => "attempt to subtract with overflow",
430 Overflow(mir::BinOp::Mul) => "attempt to multiply with overflow",
431 Overflow(mir::BinOp::Div) => "attempt to divide with overflow",
432 Overflow(mir::BinOp::Rem) => "attempt to calculate the remainder with overflow",
433 OverflowNeg => "attempt to negate with overflow",
434 Overflow(mir::BinOp::Shr) => "attempt to shift right with overflow",
435 Overflow(mir::BinOp::Shl) => "attempt to shift left with overflow",
436 Overflow(op) => bug!("{:?} cannot overflow", op),
437 DivisionByZero => "attempt to divide by zero",
438 RemainderByZero => "attempt to calculate the remainder with a divisor of zero",
439 GeneratorResumedAfterReturn => "generator resumed after completion",
440 GeneratorResumedAfterPanic => "generator resumed after panicking",
441 InfiniteLoop =>
442 "duplicate interpreter state observed here, const evaluation will never terminate",
443 }
444 }
445 }
446
447 impl<'tcx> fmt::Display for EvalError<'tcx> {
448 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
449 write!(f, "{}", self.kind)
450 }
451 }
452
453 impl<'tcx> fmt::Display for InterpError<'tcx, u64> {
454 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
455 write!(f, "{:?}", self)
456 }
457 }
458
459 impl<'tcx, O: fmt::Debug> fmt::Debug for InterpError<'tcx, O> {
460 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
461 use self::InterpError::*;
462 match *self {
463 PointerOutOfBounds { ptr, check, allocation_size } => {
464 write!(f, "Pointer must be in-bounds{} at offset {}, but is outside bounds of \
465 allocation {} which has size {}",
466 match check {
467 InboundsCheck::Live => " and live",
468 InboundsCheck::MaybeDead => "",
469 },
470 ptr.offset.bytes(), ptr.alloc_id, allocation_size.bytes())
471 },
472 ValidationFailure(ref err) => {
473 write!(f, "type validation failed: {}", err)
474 }
475 NoMirFor(ref func) => write!(f, "no mir for `{}`", func),
476 FunctionAbiMismatch(caller_abi, callee_abi) =>
477 write!(f, "tried to call a function with ABI {:?} using caller ABI {:?}",
478 callee_abi, caller_abi),
479 FunctionArgMismatch(caller_ty, callee_ty) =>
480 write!(f, "tried to call a function with argument of type {:?} \
481 passing data of type {:?}",
482 callee_ty, caller_ty),
483 FunctionRetMismatch(caller_ty, callee_ty) =>
484 write!(f, "tried to call a function with return type {:?} \
485 passing return place of type {:?}",
486 callee_ty, caller_ty),
487 FunctionArgCountMismatch =>
488 write!(f, "tried to call a function with incorrect number of arguments"),
489 BoundsCheck { ref len, ref index } =>
490 write!(f, "index out of bounds: the len is {:?} but the index is {:?}", len, index),
491 ReallocatedWrongMemoryKind(ref old, ref new) =>
492 write!(f, "tried to reallocate memory from {} to {}", old, new),
493 DeallocatedWrongMemoryKind(ref old, ref new) =>
494 write!(f, "tried to deallocate {} memory but gave {} as the kind", old, new),
495 Intrinsic(ref err) =>
496 write!(f, "{}", err),
497 InvalidChar(c) =>
498 write!(f, "tried to interpret an invalid 32-bit value as a char: {}", c),
499 AlignmentCheckFailed { required, has } =>
500 write!(f, "tried to access memory with alignment {}, but alignment {} is required",
501 has.bytes(), required.bytes()),
502 TypeNotPrimitive(ty) =>
503 write!(f, "expected primitive type, got {}", ty),
504 Layout(ref err) =>
505 write!(f, "rustc layout computation failed: {:?}", err),
506 PathNotFound(ref path) =>
507 write!(f, "Cannot find path {:?}", path),
508 MachineError(ref inner) =>
509 write!(f, "{}", inner),
510 IncorrectAllocationInformation(size, size2, align, align2) =>
511 write!(f, "incorrect alloc info: expected size {} and align {}, \
512 got size {} and align {}",
513 size.bytes(), align.bytes(), size2.bytes(), align2.bytes()),
514 Panic { ref msg, line, col, ref file } =>
515 write!(f, "the evaluated program panicked at '{}', {}:{}:{}", msg, file, line, col),
516 InvalidDiscriminant(val) =>
517 write!(f, "encountered invalid enum discriminant {}", val),
518 _ => write!(f, "{}", self.description()),
519 }
520 }
521 }