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