]> git.lizzy.rs Git - rust.git/blob - src/librustc/mir/interpret/error.rs
add Miri error variant for process exit
[rust.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(self.call_site.lo());
69                 write!(f, " at {}:{}:{}", lo.file.name, 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     /// Not actually an interprer error -- used to signal that execution has exited
233     /// with the given status code.
234     Exit(i32),
235
236     FunctionAbiMismatch(Abi, Abi),
237     FunctionArgMismatch(Ty<'tcx>, Ty<'tcx>),
238     FunctionRetMismatch(Ty<'tcx>, Ty<'tcx>),
239     FunctionArgCountMismatch,
240     NoMirFor(String),
241     UnterminatedCString(Pointer),
242     DanglingPointerDeref,
243     DoubleFree,
244     InvalidMemoryAccess,
245     InvalidFunctionPointer,
246     InvalidBool,
247     InvalidDiscriminant(ScalarMaybeUndef),
248     PointerOutOfBounds {
249         ptr: Pointer,
250         check: InboundsCheck,
251         allocation_size: Size,
252     },
253     InvalidNullPointerUsage,
254     ReadPointerAsBytes,
255     ReadBytesAsPointer,
256     ReadForeignStatic,
257     InvalidPointerMath,
258     ReadUndefBytes(Size),
259     DeadLocal,
260     InvalidBoolOp(mir::BinOp),
261     Unimplemented(String),
262     DerefFunctionPointer,
263     ExecuteMemory,
264     BoundsCheck { len: O, index: O },
265     Overflow(mir::BinOp),
266     OverflowNeg,
267     DivisionByZero,
268     RemainderByZero,
269     Intrinsic(String),
270     InvalidChar(u128),
271     StackFrameLimitReached,
272     OutOfTls,
273     TlsOutOfBounds,
274     AbiViolation(String),
275     AlignmentCheckFailed {
276         required: Align,
277         has: Align,
278     },
279     ValidationFailure(String),
280     CalledClosureAsFunction,
281     VtableForArgumentlessMethod,
282     ModifiedConstantMemory,
283     ModifiedStatic,
284     AssumptionNotHeld,
285     InlineAsm,
286     TypeNotPrimitive(Ty<'tcx>),
287     ReallocatedWrongMemoryKind(String, String),
288     DeallocatedWrongMemoryKind(String, String),
289     ReallocateNonBasePtr,
290     DeallocateNonBasePtr,
291     IncorrectAllocationInformation(Size, Size, Align, Align),
292     Layout(layout::LayoutError<'tcx>),
293     HeapAllocZeroBytes,
294     HeapAllocNonPowerOfTwoAlignment(u64),
295     Unreachable,
296     Panic {
297         msg: Symbol,
298         line: u32,
299         col: u32,
300         file: Symbol,
301     },
302     ReadFromReturnPointer,
303     PathNotFound(Vec<String>),
304     UnimplementedTraitSelection,
305     /// Abort in case type errors are reached
306     TypeckError,
307     /// Resolution can fail if we are in a too generic context
308     TooGeneric,
309     /// Cannot compute this constant because it depends on another one
310     /// which already produced an error
311     ReferencedConstant,
312     GeneratorResumedAfterReturn,
313     GeneratorResumedAfterPanic,
314     InfiniteLoop,
315 }
316
317 pub type EvalResult<'tcx, T = ()> = Result<T, EvalError<'tcx>>;
318
319 impl<'tcx, O> InterpError<'tcx, O> {
320     pub fn description(&self) -> &str {
321         use self::InterpError::*;
322         match *self {
323             MachineError(ref inner) => inner,
324             Exit(..) =>
325                 "exited",
326             FunctionAbiMismatch(..) | FunctionArgMismatch(..) | FunctionRetMismatch(..)
327             | FunctionArgCountMismatch =>
328                 "tried to call a function through a function pointer of incompatible type",
329             InvalidMemoryAccess =>
330                 "tried to access memory through an invalid pointer",
331             DanglingPointerDeref =>
332                 "dangling pointer was dereferenced",
333             DoubleFree =>
334                 "tried to deallocate dangling pointer",
335             InvalidFunctionPointer =>
336                 "tried to use a function pointer after offsetting it",
337             InvalidBool =>
338                 "invalid boolean value read",
339             InvalidDiscriminant(..) =>
340                 "invalid enum discriminant value read",
341             PointerOutOfBounds { .. } =>
342                 "pointer offset outside bounds of allocation",
343             InvalidNullPointerUsage =>
344                 "invalid use of NULL pointer",
345             ValidationFailure(..) =>
346                 "type validation failed",
347             ReadPointerAsBytes =>
348                 "a raw memory access tried to access part of a pointer value as raw bytes",
349             ReadBytesAsPointer =>
350                 "a memory access tried to interpret some bytes as a pointer",
351             ReadForeignStatic =>
352                 "tried to read from foreign (extern) static",
353             InvalidPointerMath =>
354                 "attempted to do invalid arithmetic on pointers that would leak base addresses, \
355                 e.g., comparing pointers into different allocations",
356             ReadUndefBytes(_) =>
357                 "attempted to read undefined bytes",
358             DeadLocal =>
359                 "tried to access a dead local variable",
360             InvalidBoolOp(_) =>
361                 "invalid boolean operation",
362             Unimplemented(ref msg) => msg,
363             DerefFunctionPointer =>
364                 "tried to dereference a function pointer",
365             ExecuteMemory =>
366                 "tried to treat a memory pointer as a function pointer",
367             BoundsCheck{..} =>
368                 "array index out of bounds",
369             Intrinsic(..) =>
370                 "intrinsic failed",
371             NoMirFor(..) =>
372                 "mir not found",
373             InvalidChar(..) =>
374                 "tried to interpret an invalid 32-bit value as a char",
375             StackFrameLimitReached =>
376                 "reached the configured maximum number of stack frames",
377             OutOfTls =>
378                 "reached the maximum number of representable TLS keys",
379             TlsOutOfBounds =>
380                 "accessed an invalid (unallocated) TLS key",
381             AbiViolation(ref msg) => msg,
382             AlignmentCheckFailed{..} =>
383                 "tried to execute a misaligned read or write",
384             CalledClosureAsFunction =>
385                 "tried to call a closure through a function pointer",
386             VtableForArgumentlessMethod =>
387                 "tried to call a vtable function without arguments",
388             ModifiedConstantMemory =>
389                 "tried to modify constant memory",
390             ModifiedStatic =>
391                 "tried to modify a static's initial value from another static's initializer",
392             AssumptionNotHeld =>
393                 "`assume` argument was false",
394             InlineAsm =>
395                 "miri does not support inline assembly",
396             TypeNotPrimitive(_) =>
397                 "expected primitive type, got nonprimitive",
398             ReallocatedWrongMemoryKind(_, _) =>
399                 "tried to reallocate memory from one kind to another",
400             DeallocatedWrongMemoryKind(_, _) =>
401                 "tried to deallocate memory of the wrong kind",
402             ReallocateNonBasePtr =>
403                 "tried to reallocate with a pointer not to the beginning of an existing object",
404             DeallocateNonBasePtr =>
405                 "tried to deallocate with a pointer not to the beginning of an existing object",
406             IncorrectAllocationInformation(..) =>
407                 "tried to deallocate or reallocate using incorrect alignment or size",
408             Layout(_) =>
409                 "rustc layout computation failed",
410             UnterminatedCString(_) =>
411                 "attempted to get length of a null terminated string, but no null found before end \
412                 of allocation",
413             HeapAllocZeroBytes =>
414                 "tried to re-, de- or allocate zero bytes on the heap",
415             HeapAllocNonPowerOfTwoAlignment(_) =>
416                 "tried to re-, de-, or allocate heap memory with alignment that is not a power of \
417                 two",
418             Unreachable =>
419                 "entered unreachable code",
420             Panic { .. } =>
421                 "the evaluated program panicked",
422             ReadFromReturnPointer =>
423                 "tried to read from the return pointer",
424             PathNotFound(_) =>
425                 "a path could not be resolved, maybe the crate is not loaded",
426             UnimplementedTraitSelection =>
427                 "there were unresolved type arguments during trait selection",
428             TypeckError =>
429                 "encountered constants with type errors, stopping evaluation",
430             TooGeneric =>
431                 "encountered overly generic constant",
432             ReferencedConstant =>
433                 "referenced constant has errors",
434             Overflow(mir::BinOp::Add) => "attempt to add with overflow",
435             Overflow(mir::BinOp::Sub) => "attempt to subtract with overflow",
436             Overflow(mir::BinOp::Mul) => "attempt to multiply with overflow",
437             Overflow(mir::BinOp::Div) => "attempt to divide with overflow",
438             Overflow(mir::BinOp::Rem) => "attempt to calculate the remainder with overflow",
439             OverflowNeg => "attempt to negate with overflow",
440             Overflow(mir::BinOp::Shr) => "attempt to shift right with overflow",
441             Overflow(mir::BinOp::Shl) => "attempt to shift left with overflow",
442             Overflow(op) => bug!("{:?} cannot overflow", op),
443             DivisionByZero => "attempt to divide by zero",
444             RemainderByZero => "attempt to calculate the remainder with a divisor of zero",
445             GeneratorResumedAfterReturn => "generator resumed after completion",
446             GeneratorResumedAfterPanic => "generator resumed after panicking",
447             InfiniteLoop =>
448                 "duplicate interpreter state observed here, const evaluation will never terminate",
449         }
450     }
451 }
452
453 impl<'tcx> fmt::Display for EvalError<'tcx> {
454     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
455         write!(f, "{}", self.kind)
456     }
457 }
458
459 impl<'tcx> fmt::Display for InterpError<'tcx, u64> {
460     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
461         write!(f, "{:?}", self)
462     }
463 }
464
465 impl<'tcx, O: fmt::Debug> fmt::Debug for InterpError<'tcx, O> {
466     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
467         use self::InterpError::*;
468         match *self {
469             PointerOutOfBounds { ptr, check, allocation_size } => {
470                 write!(f, "Pointer must be in-bounds{} at offset {}, but is outside bounds of \
471                            allocation {} which has size {}",
472                        match check {
473                            InboundsCheck::Live => " and live",
474                            InboundsCheck::MaybeDead => "",
475                        },
476                        ptr.offset.bytes(), ptr.alloc_id, allocation_size.bytes())
477             },
478             ValidationFailure(ref err) => {
479                 write!(f, "type validation failed: {}", err)
480             }
481             NoMirFor(ref func) => write!(f, "no mir for `{}`", func),
482             FunctionAbiMismatch(caller_abi, callee_abi) =>
483                 write!(f, "tried to call a function with ABI {:?} using caller ABI {:?}",
484                     callee_abi, caller_abi),
485             FunctionArgMismatch(caller_ty, callee_ty) =>
486                 write!(f, "tried to call a function with argument of type {:?} \
487                            passing data of type {:?}",
488                     callee_ty, caller_ty),
489             FunctionRetMismatch(caller_ty, callee_ty) =>
490                 write!(f, "tried to call a function with return type {:?} \
491                            passing return place of type {:?}",
492                     callee_ty, caller_ty),
493             FunctionArgCountMismatch =>
494                 write!(f, "tried to call a function with incorrect number of arguments"),
495             BoundsCheck { ref len, ref index } =>
496                 write!(f, "index out of bounds: the len is {:?} but the index is {:?}", len, index),
497             ReallocatedWrongMemoryKind(ref old, ref new) =>
498                 write!(f, "tried to reallocate memory from {} to {}", old, new),
499             DeallocatedWrongMemoryKind(ref old, ref new) =>
500                 write!(f, "tried to deallocate {} memory but gave {} as the kind", old, new),
501             Intrinsic(ref err) =>
502                 write!(f, "{}", err),
503             InvalidChar(c) =>
504                 write!(f, "tried to interpret an invalid 32-bit value as a char: {}", c),
505             AlignmentCheckFailed { required, has } =>
506                write!(f, "tried to access memory with alignment {}, but alignment {} is required",
507                       has.bytes(), required.bytes()),
508             TypeNotPrimitive(ty) =>
509                 write!(f, "expected primitive type, got {}", ty),
510             Layout(ref err) =>
511                 write!(f, "rustc layout computation failed: {:?}", err),
512             PathNotFound(ref path) =>
513                 write!(f, "Cannot find path {:?}", path),
514             MachineError(ref inner) =>
515                 write!(f, "{}", inner),
516             IncorrectAllocationInformation(size, size2, align, align2) =>
517                 write!(f, "incorrect alloc info: expected size {} and align {}, \
518                            got size {} and align {}",
519                     size.bytes(), align.bytes(), size2.bytes(), align2.bytes()),
520             Panic { ref msg, line, col, ref file } =>
521                 write!(f, "the evaluated program panicked at '{}', {}:{}:{}", msg, file, line, col),
522             InvalidDiscriminant(val) =>
523                 write!(f, "encountered invalid enum discriminant {}", val),
524             Exit(code) =>
525                 write!(f, "exited with status code {}", code),
526             _ => write!(f, "{}", self.description()),
527         }
528     }
529 }