diff --git a/src/librustc_middle/mir/interpret/error.rs b/src/librustc_middle/mir/interpret/error.rs index 1c4309dbe3a5..ffe71eb3a092 100644 --- a/src/librustc_middle/mir/interpret/error.rs +++ b/src/librustc_middle/mir/interpret/error.rs @@ -3,8 +3,7 @@ use super::{AllocId, Pointer, RawConst, ScalarMaybeUndef}; use crate::mir::interpret::ConstValue; use crate::ty::layout::LayoutError; use crate::ty::query::TyCtxtAt; -use crate::ty::tls; -use crate::ty::{self, layout, Ty}; +use crate::ty::{self, layout, tls, FnSig, Ty}; use rustc_data_structures::sync::Lock; use rustc_errors::{struct_span_err, DiagnosticBuilder, ErrorReported}; @@ -329,7 +328,7 @@ impl fmt::Display for CheckInAllocMsg { } /// Error information for when the program caused Undefined Behavior. -pub enum UndefinedBehaviorInfo { +pub enum UndefinedBehaviorInfo<'tcx> { /// Free-form case. Only for errors that are never caught! Ub(String), /// Unreachable code was executed. @@ -347,6 +346,8 @@ pub enum UndefinedBehaviorInfo { PointerArithOverflow, /// Invalid metadata in a wide pointer (using `str` to avoid allocations). InvalidMeta(&'static str), + /// Invalid drop function in vtable. + InvalidDropFn(FnSig<'tcx>), /// Reading a C string that does not end within its allocation. UnterminatedCString(Pointer), /// Dereferencing a dangling pointer after it got freed. @@ -393,7 +394,7 @@ pub enum UndefinedBehaviorInfo { }, } -impl fmt::Display for UndefinedBehaviorInfo { +impl fmt::Display for UndefinedBehaviorInfo<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use UndefinedBehaviorInfo::*; match self { @@ -406,6 +407,11 @@ impl fmt::Display for UndefinedBehaviorInfo { RemainderByZero => write!(f, "calculating the remainder with a divisor of zero"), PointerArithOverflow => write!(f, "overflowing in-bounds pointer arithmetic"), InvalidMeta(msg) => write!(f, "invalid metadata in wide pointer: {}", msg), + InvalidDropFn(sig) => write!( + f, + "invalid drop function signature: got {}, expected exactly one argument which must be a pointer type", + sig + ), UnterminatedCString(p) => write!( f, "reading a null-terminated string starting at {} with no null found before end of allocation", @@ -448,9 +454,7 @@ impl fmt::Display for UndefinedBehaviorInfo { InvalidFunctionPointer(p) => { write!(f, "using {} as function pointer but it does not point to a function", p) } - InvalidStr(err) => { - write!(f, "this string is not valid UTF-8: {}", err) - } + InvalidStr(err) => write!(f, "this string is not valid UTF-8: {}", err), InvalidUndefBytes(Some(p)) => write!( f, "reading uninitialized memory at {}, but this operation requires initialized memory", @@ -554,7 +558,7 @@ impl dyn MachineStopType { pub enum InterpError<'tcx> { /// The program caused undefined behavior. - UndefinedBehavior(UndefinedBehaviorInfo), + UndefinedBehavior(UndefinedBehaviorInfo<'tcx>), /// The program did something the interpreter does not support (some of these *might* be UB /// but the interpreter is not sure). Unsupported(UnsupportedOpInfo), diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index e8ef330c76cf..db836d88dd05 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -327,8 +327,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn read_str(&self, mplace: MPlaceTy<'tcx, M::PointerTag>) -> InterpResult<'tcx, &str> { let len = mplace.len(self)?; let bytes = self.memory.read_bytes(mplace.ptr, Size::from_bytes(len))?; - let str = ::std::str::from_utf8(bytes) - .map_err(|err| err_ub!(InvalidStr(err)))?; + let str = ::std::str::from_utf8(bytes).map_err(|err| err_ub!(InvalidStr(err)))?; Ok(str) } diff --git a/src/librustc_mir/interpret/traits.rs b/src/librustc_mir/interpret/traits.rs index 7edd787c986b..23673487d2b2 100644 --- a/src/librustc_mir/interpret/traits.rs +++ b/src/librustc_mir/interpret/traits.rs @@ -147,13 +147,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // The drop function takes `*mut T` where `T` is the type being dropped, so get that. let args = fn_sig.inputs(); if args.len() != 1 { - throw_ub_format!("drop fn should have 1 argument, but signature is {:?}", fn_sig); + throw_ub!(InvalidDropFn(fn_sig)); } let ty = args[0] .builtin_deref(true) - .ok_or_else(|| { - err_ub_format!("drop fn argument type {} is not a pointer type", args[0]) - })? + .ok_or_else(|| err_ub!(InvalidDropFn(fn_sig)))? .ty; Ok((drop_instance, ty)) } diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index 2e1138d1d070..2c62070b1b1d 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -313,6 +313,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' try_validation!( self.ecx.read_drop_type_from_vtable(vtable), self.path, + err_ub!(InvalidDropFn(..)) | err_ub!(DanglingIntPointer(..)) | err_ub!(InvalidFunctionPointer(..)) | err_unsup!(ReadBytesAsPointer) =>