From 0468929ce3f3e142287124a37f3318cc3b53a52b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 4 Mar 2020 08:40:13 +0100 Subject: [PATCH 1/5] move error allocation test to error.rs --- src/librustc/mir/interpret/error.rs | 18 +++++++++++- src/librustc_mir/transform/const_prop.rs | 35 ++++++------------------ 2 files changed, 26 insertions(+), 27 deletions(-) diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index 28e197b2a7f..2310867400c 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -354,7 +354,7 @@ pub enum UnsupportedOpInfo<'tcx> { Unsupported(String), /// When const-prop encounters a situation it does not support, it raises this error. - /// This must not allocate for performance reasons. + /// This must not allocate for performance reasons (hence `str`, not `String`). ConstPropUnsupported(&'tcx str), // -- Everything below is not categorized yet -- @@ -612,3 +612,19 @@ impl fmt::Debug for InterpError<'_> { } } } + +impl InterpError<'_> { + /// Some errors allocate to be created as they contain free-from strings. + /// And sometiems we want to be sure that did not happen as it is a + /// waste of resources. + pub fn allocates(&self) -> bool { + match self { + InterpError::MachineStop(_) + | InterpError::Unsupported(UnsupportedOpInfo::Unsupported(_)) + | InterpError::Unsupported(UnsupportedOpInfo::ValidationFailure(_)) + | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::Ub(_)) + | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::UbExperimental(_)) => true, + _ => false, + } + } +} diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 0560f77f5c9..1fea9281b93 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -404,32 +404,15 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { let r = match f(self) { Ok(val) => Some(val), Err(error) => { - use rustc::mir::interpret::{ - InterpError::*, UndefinedBehaviorInfo, UnsupportedOpInfo, - }; - match error.kind { - MachineStop(_) => bug!("ConstProp does not stop"), - - // Some error shouldn't come up because creating them causes - // an allocation, which we should avoid. When that happens, - // dedicated error variants should be introduced instead. - // Only test this in debug builds though to avoid disruptions. - Unsupported(UnsupportedOpInfo::Unsupported(_)) - | Unsupported(UnsupportedOpInfo::ValidationFailure(_)) - | UndefinedBehavior(UndefinedBehaviorInfo::Ub(_)) - | UndefinedBehavior(UndefinedBehaviorInfo::UbExperimental(_)) - if cfg!(debug_assertions) => - { - bug!("const-prop encountered allocating error: {:?}", error.kind); - } - - Unsupported(_) - | UndefinedBehavior(_) - | InvalidProgram(_) - | ResourceExhaustion(_) => { - // Ignore these errors. - } - } + // Some errors shouldn't come up because creating them causes + // an allocation, which we should avoid. When that happens, + // dedicated error variants should be introduced instead. + // Only test this in debug builds though to avoid disruptions. + debug_assert!( + !error.kind.allocates(), + "const-prop encountered allocating error: {}", + error + ); None } }; From 938f8522ecf6c463bc06503251a23c3ded35ca25 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 4 Mar 2020 08:43:03 +0100 Subject: [PATCH 2/5] miri validation: debug-complain about unexpected errors --- src/librustc_mir/interpret/validity.rs | 27 ++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index 84717cbeaa9..b3de44f36d2 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -46,6 +46,8 @@ macro_rules! try_validation { ($e:expr, $what:expr, $where:expr, $details:expr) => {{ match $e { Ok(x) => x, + // We re-throw the error, so we are okay with allocation: + // this can only slow down builds that fail anyway. Err(_) => throw_validation_failure!($what, $where, $details), } }}; @@ -53,6 +55,8 @@ macro_rules! try_validation { ($e:expr, $what:expr, $where:expr) => {{ match $e { Ok(x) => x, + // We re-throw the error, so we are okay with allocation: + // this can only slow down builds that fail anyway. Err(_) => throw_validation_failure!($what, $where), } }}; @@ -359,10 +363,13 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M format_args!("a dangling {} (created from integer)", kind), self.path ), - _ => throw_validation_failure!( - format_args!("a dangling {} (not entirely in bounds)", kind), - self.path - ), + err_unsup!(PointerOutOfBounds { .. }) | err_unsup!(DanglingPointerDeref) => { + throw_validation_failure!( + format_args!("a dangling {} (not entirely in bounds)", kind), + self.path + ) + } + _ => bug!("Unexpected error during ptr inbounds test: {}", err), } } }; @@ -638,6 +645,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> err_unsup!(ReadPointerAsBytes) => { throw_validation_failure!("a pointer", self.path, "plain (non-pointer) bytes") } + // Propagate upwards (that will also check for unexpected errors). _ => return Err(err), }, } @@ -797,7 +805,14 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Try to cast to ptr *once* instead of all the time. let op = self.force_op_ptr(op).unwrap_or(op); - // Run it - visitor.visit_value(op) + // Run it. + match visitor.visit_value(op) { + Ok(()) => Ok(()), + Err(err) if matches!(err.kind, err_unsup!(ValidationFailure { .. })) => Err(err), + Err(err) if cfg!(debug_assertions) => { + bug!("Unexpected error during validation: {}", err) + } + Err(err) => Err(err), + } } } From 4971d03ccfe9452753deb84fd958fd0b0e63f156 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 5 Mar 2020 23:31:39 +0100 Subject: [PATCH 3/5] fix some cases of unexpected exceptions leaving validation --- src/librustc/mir/interpret/error.rs | 13 ++-- src/librustc_mir/const_eval/eval_queries.rs | 7 +- src/librustc_mir/interpret/eval_context.rs | 12 +--- src/librustc_mir/interpret/place.rs | 8 +-- src/librustc_mir/interpret/validity.rs | 64 +++++++++++++++---- src/librustc_mir/transform/const_prop.rs | 5 +- src/test/ui/consts/const-eval/dangling.rs | 2 +- src/test/ui/consts/const-eval/dangling.stderr | 2 +- src/test/ui/consts/const-eval/ub-wide-ptr.rs | 6 +- .../ui/consts/const-eval/ub-wide-ptr.stderr | 58 +++++++++++------ .../ui/consts/const-points-to-static.stderr | 2 +- src/test/ui/consts/issue-63952.stderr | 2 +- .../const_refers_to_static.stderr | 4 +- 13 files changed, 122 insertions(+), 63 deletions(-) diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index 2310867400c..731c3ee0d6a 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -245,7 +245,7 @@ fn print_backtrace(backtrace: &mut Backtrace) { eprintln!("\n\nAn error occurred in miri:\n{:?}", backtrace); } -impl From for InterpErrorInfo<'tcx> { +impl From for InterpErrorInfo<'_> { fn from(err: ErrorHandled) -> Self { match err { ErrorHandled::Reported => err_inval!(ReferencedConstant), @@ -291,7 +291,7 @@ pub enum InvalidProgramInfo<'tcx> { Layout(layout::LayoutError<'tcx>), } -impl fmt::Debug for InvalidProgramInfo<'tcx> { +impl fmt::Debug for InvalidProgramInfo<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use InvalidProgramInfo::*; match self { @@ -304,7 +304,7 @@ impl fmt::Debug for InvalidProgramInfo<'tcx> { } /// 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), /// Free-form case for experimental UB. Only for errors that are never caught! @@ -321,9 +321,11 @@ pub enum UndefinedBehaviorInfo { RemainderByZero, /// Overflowing inbounds pointer arithmetic. PointerArithOverflow, + /// Invalid metadata in a wide pointer (using `str` to avoid allocations). + InvalidMeta(&'tcx str), } -impl fmt::Debug for UndefinedBehaviorInfo { +impl fmt::Debug for UndefinedBehaviorInfo<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use UndefinedBehaviorInfo::*; match self { @@ -338,6 +340,7 @@ impl fmt::Debug for UndefinedBehaviorInfo { DivisionByZero => write!(f, "dividing by zero"), 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), } } } @@ -577,7 +580,7 @@ impl fmt::Debug for ResourceExhaustionInfo { 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<'tcx>), diff --git a/src/librustc_mir/const_eval/eval_queries.rs b/src/librustc_mir/const_eval/eval_queries.rs index 7a8e61db6d0..ffbff00cf37 100644 --- a/src/librustc_mir/const_eval/eval_queries.rs +++ b/src/librustc_mir/const_eval/eval_queries.rs @@ -186,7 +186,12 @@ fn validate_and_turn_into_const<'tcx>( if cid.promoted.is_none() { let mut ref_tracking = RefTracking::new(mplace); while let Some((mplace, path)) = ref_tracking.todo.pop() { - ecx.validate_operand(mplace.into(), path, Some(&mut ref_tracking))?; + ecx.const_validate_operand( + mplace.into(), + path, + &mut ref_tracking, + /*may_ref_to_static*/ is_static, + )?; } } // Now that we validated, turn this into a proper constant. diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index e683422e611..9b28b7a20c0 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -457,10 +457,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Check if this brought us over the size limit. if size.bytes() >= self.tcx.data_layout().obj_size_bound() { - throw_ub_format!( - "wide pointer metadata contains invalid information: \ - total size is bigger than largest supported object" - ); + throw_ub!(InvalidMeta("total size is bigger than largest supported object")); } Ok(Some((size, align))) } @@ -476,10 +473,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Make sure the slice is not too big. let size = elem.size.checked_mul(len, &*self.tcx).ok_or_else(|| { - err_ub_format!( - "invalid slice: \ - total size is bigger than largest supported object" - ) + err_ub!(InvalidMeta("slice is bigger than largest supported object")) })?; Ok(Some((size, elem.align.abi))) } @@ -685,7 +679,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // invariant -- that is, unless a function somehow has a ptr to // its return place... but the way MIR is currently generated, the // return place is always a local and then this cannot happen. - self.validate_operand(self.place_to_op(return_place)?, vec![], None)?; + self.validate_operand(self.place_to_op(return_place)?)?; } } else { // Uh, that shouldn't happen... the function did not intend to return diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index fff9c740f7e..a4815b9696e 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -689,7 +689,7 @@ where if M::enforce_validity(self) { // Data got changed, better make sure it matches the type! - self.validate_operand(self.place_to_op(dest)?, vec![], None)?; + self.validate_operand(self.place_to_op(dest)?)?; } Ok(()) @@ -706,7 +706,7 @@ where if M::enforce_validity(self) { // Data got changed, better make sure it matches the type! - self.validate_operand(dest.into(), vec![], None)?; + self.validate_operand(dest.into())?; } Ok(()) @@ -843,7 +843,7 @@ where if M::enforce_validity(self) { // Data got changed, better make sure it matches the type! - self.validate_operand(self.place_to_op(dest)?, vec![], None)?; + self.validate_operand(self.place_to_op(dest)?)?; } Ok(()) @@ -951,7 +951,7 @@ where if M::enforce_validity(self) { // Data got changed, better make sure it matches the type! - self.validate_operand(dest.into(), vec![], None)?; + self.validate_operand(dest.into())?; } Ok(()) diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index b3de44f36d2..05bb010959b 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -171,6 +171,7 @@ struct ValidityVisitor<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> { path: Vec, ref_tracking_for_consts: Option<&'rt mut RefTracking, Vec>>, + may_ref_to_static: bool, ecx: &'rt InterpCx<'mir, 'tcx, M>, } @@ -324,9 +325,17 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M self.check_wide_ptr_meta(place.meta, place.layout)?; } // Make sure this is dereferenceable and all. - let (size, align) = self - .ecx - .size_and_align_of(place.meta, place.layout)? + let size_and_align = match self.ecx.size_and_align_of(place.meta, place.layout) { + Ok(res) => res, + Err(err) => match err.kind { + err_ub!(InvalidMeta(msg)) => throw_validation_failure!( + format_args!("invalid {} metadata: {}", kind, msg), + self.path + ), + _ => bug!("Unexpected error during ptr size_and_align_of: {}", err), + }, + }; + let (size, align) = size_and_align // for the purpose of validity, consider foreign types to have // alignment and size determined by the layout (size will be 0, // alignment should take attributes into account). @@ -387,6 +396,12 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M if !did.is_local() || self.ecx.tcx.is_foreign_item(did) { return Ok(()); } + if !self.may_ref_to_static && self.ecx.tcx.is_static(did) { + throw_validation_failure!( + format_args!("a {} pointing to a static variable", kind), + self.path + ); + } } } // Proceed recursively even for ZST, no reason to skip them! @@ -781,26 +796,20 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> } impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { - /// This function checks the data at `op`. `op` is assumed to cover valid memory if it - /// is an indirect operand. - /// It will error if the bits at the destination do not match the ones described by the layout. - /// - /// `ref_tracking_for_consts` can be `None` to avoid recursive checking below references. - /// This also toggles between "run-time" (no recursion) and "compile-time" (with recursion) - /// validation (e.g., pointer values are fine in integers at runtime) and various other const - /// specific validation checks. - pub fn validate_operand( + fn validate_operand_internal( &self, op: OpTy<'tcx, M::PointerTag>, path: Vec, ref_tracking_for_consts: Option< &mut RefTracking, Vec>, >, + may_ref_to_static: bool, ) -> InterpResult<'tcx> { - trace!("validate_operand: {:?}, {:?}", *op, op.layout.ty); + trace!("validate_operand_internal: {:?}, {:?}", *op, op.layout.ty); // Construct a visitor - let mut visitor = ValidityVisitor { path, ref_tracking_for_consts, ecx: self }; + let mut visitor = + ValidityVisitor { path, ref_tracking_for_consts, may_ref_to_static, ecx: self }; // Try to cast to ptr *once* instead of all the time. let op = self.force_op_ptr(op).unwrap_or(op); @@ -815,4 +824,31 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Err(err) => Err(err), } } + + /// This function checks the data at `op` to be const-valid. + /// `op` is assumed to cover valid memory if it is an indirect operand. + /// It will error if the bits at the destination do not match the ones described by the layout. + /// + /// `ref_tracking` is used to record references that we encounter so that they + /// can be checked recursively by an outside driving loop. + /// + /// `may_ref_to_static` controls whether references are allowed to point to statics. + #[inline(always)] + pub fn const_validate_operand( + &self, + op: OpTy<'tcx, M::PointerTag>, + path: Vec, + ref_tracking: &mut RefTracking, Vec>, + may_ref_to_static: bool, + ) -> InterpResult<'tcx> { + self.validate_operand_internal(op, path, Some(ref_tracking), may_ref_to_static) + } + + /// This function checks the data at `op` to be runtime-valid. + /// `op` is assumed to cover valid memory if it is an indirect operand. + /// It will error if the bits at the destination do not match the ones described by the layout. + #[inline(always)] + pub fn validate_operand(&self, op: OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> { + self.validate_operand_internal(op, vec![], None, false) + } } diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 1fea9281b93..a07c8575b30 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -637,11 +637,12 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { source_info: SourceInfo, ) { trace!("attepting to replace {:?} with {:?}", rval, value); - if let Err(e) = self.ecx.validate_operand( + if let Err(e) = self.ecx.const_validate_operand( value, vec![], // FIXME: is ref tracking too expensive? - Some(&mut interpret::RefTracking::empty()), + &mut interpret::RefTracking::empty(), + /*may_ref_to_static*/ true, ) { trace!("validation error, attempt failed: {:?}", e); return; diff --git a/src/test/ui/consts/const-eval/dangling.rs b/src/test/ui/consts/const-eval/dangling.rs index b5d72d46f28..c6b8e8eb611 100644 --- a/src/test/ui/consts/const-eval/dangling.rs +++ b/src/test/ui/consts/const-eval/dangling.rs @@ -6,7 +6,7 @@ use std::{mem, usize}; const TEST: () = { unsafe { //~ NOTE let slice: *const [u8] = mem::transmute((1usize, usize::MAX)); let _val = &*slice; //~ ERROR: any use of this value will cause an error - //~^ NOTE: total size is bigger than largest supported object + //~^ NOTE: slice is bigger than largest supported object //~^^ on by default } }; diff --git a/src/test/ui/consts/const-eval/dangling.stderr b/src/test/ui/consts/const-eval/dangling.stderr index 286de080097..b9ddc93b03b 100644 --- a/src/test/ui/consts/const-eval/dangling.stderr +++ b/src/test/ui/consts/const-eval/dangling.stderr @@ -4,7 +4,7 @@ error: any use of this value will cause an error LL | / const TEST: () = { unsafe { LL | | let slice: *const [u8] = mem::transmute((1usize, usize::MAX)); LL | | let _val = &*slice; - | | ^^^^^^^ invalid slice: total size is bigger than largest supported object + | | ^^^^^^^ invalid metadata in wide pointer: slice is bigger than largest supported object LL | | LL | | LL | | } }; diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.rs b/src/test/ui/consts/const-eval/ub-wide-ptr.rs index 26d37884746..2d48309b727 100644 --- a/src/test/ui/consts/const-eval/ub-wide-ptr.rs +++ b/src/test/ui/consts/const-eval/ub-wide-ptr.rs @@ -31,12 +31,16 @@ const STR_VALID: &str = unsafe { mem::transmute((&42u8, 1usize)) }; // bad str const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) }; //~^ ERROR it is undefined behavior to use this value +const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },); +//~^ ERROR it is undefined behavior to use this value // bad str const STR_LENGTH_PTR: &str = unsafe { mem::transmute((&42u8, &3)) }; //~^ ERROR it is undefined behavior to use this value // bad str in user-defined unsized type const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) }; //~^ ERROR it is undefined behavior to use this value +const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) }; +//~^ ERROR it is undefined behavior to use this value // invalid UTF-8 const STR_NO_UTF8: &str = unsafe { mem::transmute::<&[u8], _>(&[0xFF]) }; @@ -83,7 +87,7 @@ const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute // # raw slice const RAW_SLICE_VALID: *const [u8] = unsafe { mem::transmute((&42u8, 1usize)) }; // ok const RAW_SLICE_TOO_LONG: *const [u8] = unsafe { mem::transmute((&42u8, 999usize)) }; // ok because raw -const RAW_SLICE_MUCH_TOO_LONG: *const [u8] = unsafe { mem::transmute((&42u8, usize::max_value())) }; // ok because raw +const RAW_SLICE_MUCH_TOO_LONG: *const [u8] = unsafe { mem::transmute((&42u8, usize::MAX)) }; // ok because raw const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe { //~^ ERROR it is undefined behavior to use this value let uninit_len = MaybeUninit:: { uninit: () }; diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.stderr b/src/test/ui/consts/const-eval/ub-wide-ptr.stderr index 22adf0e55ee..a562c64b124 100644 --- a/src/test/ui/consts/const-eval/ub-wide-ptr.stderr +++ b/src/test/ui/consts/const-eval/ub-wide-ptr.stderr @@ -7,7 +7,15 @@ LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:35:1 + --> $DIR/ub-wide-ptr.rs:34:1 + | +LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object at .0 + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:37:1 | LL | const STR_LENGTH_PTR: &str = unsafe { mem::transmute((&42u8, &3)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in wide pointer @@ -15,7 +23,7 @@ LL | const STR_LENGTH_PTR: &str = unsafe { mem::transmute((&42u8, &3)) }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:38:1 + --> $DIR/ub-wide-ptr.rs:40:1 | LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in wide pointer @@ -25,13 +33,21 @@ LL | const MY_STR_LENGTH_PTR: &MyStr = unsafe { mem::transmute((&42u8, &3)) }; error[E0080]: it is undefined behavior to use this value --> $DIR/ub-wide-ptr.rs:42:1 | +LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object + | + = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. + +error[E0080]: it is undefined behavior to use this value + --> $DIR/ub-wide-ptr.rs:46:1 + | LL | const STR_NO_UTF8: &str = unsafe { mem::transmute::<&[u8], _>(&[0xFF]) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized or non-UTF-8 data in str at . | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:45:1 + --> $DIR/ub-wide-ptr.rs:49:1 | LL | const MYSTR_NO_UTF8: &MyStr = unsafe { mem::transmute::<&[u8], _>(&[0xFF]) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized or non-UTF-8 data in str at ..0 @@ -39,7 +55,7 @@ LL | const MYSTR_NO_UTF8: &MyStr = unsafe { mem::transmute::<&[u8], _>(&[0xFF]) = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:52:1 + --> $DIR/ub-wide-ptr.rs:56:1 | LL | / const SLICE_LENGTH_UNINIT: &[u8] = unsafe { LL | | @@ -51,7 +67,7 @@ LL | | }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:58:1 + --> $DIR/ub-wide-ptr.rs:62:1 | LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling reference (not entirely in bounds) @@ -59,7 +75,7 @@ LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:61:1 + --> $DIR/ub-wide-ptr.rs:65:1 | LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in wide pointer @@ -67,7 +83,7 @@ LL | const SLICE_LENGTH_PTR: &[u8] = unsafe { mem::transmute((&42u8, &3)) }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:64:1 + --> $DIR/ub-wide-ptr.rs:68:1 | LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling box (not entirely in bounds) @@ -75,7 +91,7 @@ LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999us = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:67:1 + --> $DIR/ub-wide-ptr.rs:71:1 | LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in wide pointer @@ -83,7 +99,7 @@ LL | const SLICE_LENGTH_PTR_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, &3) = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:71:1 + --> $DIR/ub-wide-ptr.rs:75:1 | LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .[0], but expected a boolean @@ -91,7 +107,7 @@ LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:77:1 + --> $DIR/ub-wide-ptr.rs:81:1 | LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at ..0, but expected a boolean @@ -99,7 +115,7 @@ LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3 = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:80:1 + --> $DIR/ub-wide-ptr.rs:84:1 | LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at ..1[0], but expected a boolean @@ -107,7 +123,7 @@ LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::tran = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:87:1 + --> $DIR/ub-wide-ptr.rs:91:1 | LL | / const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe { LL | | @@ -119,7 +135,7 @@ LL | | }; = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:95:1 + --> $DIR/ub-wide-ptr.rs:99:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_1: &dyn Trait = unsafe { mem::transmute((&92u8, &3u8)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable @@ -127,7 +143,7 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_1: &dyn Trait = unsafe { mem::transmute((&92u8 = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:98:1 + --> $DIR/ub-wide-ptr.rs:102:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_2: &dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable @@ -135,7 +151,7 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_2: &dyn Trait = unsafe { mem::transmute((&92u8 = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:101:1 + --> $DIR/ub-wide-ptr.rs:105:1 | LL | const TRAIT_OBJ_INT_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, 4usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable @@ -143,7 +159,7 @@ LL | const TRAIT_OBJ_INT_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, 4u = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:105:1 + --> $DIR/ub-wide-ptr.rs:109:1 | LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .., but expected a boolean @@ -151,7 +167,7 @@ LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:109:1 + --> $DIR/ub-wide-ptr.rs:113:1 | LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable @@ -159,7 +175,7 @@ LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: it is undefined behavior to use this value - --> $DIR/ub-wide-ptr.rs:111:1 + --> $DIR/ub-wide-ptr.rs:115:1 | LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling or unaligned vtable pointer in wide pointer or too small vtable @@ -167,17 +183,17 @@ LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transm = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. error[E0080]: could not evaluate static initializer - --> $DIR/ub-wide-ptr.rs:117:5 + --> $DIR/ub-wide-ptr.rs:121:5 | LL | mem::transmute::<_, &dyn Trait>((&92u8, 0usize)) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid use of NULL pointer error[E0080]: could not evaluate static initializer - --> $DIR/ub-wide-ptr.rs:121:5 + --> $DIR/ub-wide-ptr.rs:125:5 | LL | mem::transmute::<_, &dyn Trait>((&92u8, &3u64)) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Memory access failed: pointer must be in-bounds at offset N, but is outside bounds of allocation N which has size N -error: aborting due to 22 previous errors +error: aborting due to 24 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-points-to-static.stderr b/src/test/ui/consts/const-points-to-static.stderr index 8949358e293..f2ca7ff7825 100644 --- a/src/test/ui/consts/const-points-to-static.stderr +++ b/src/test/ui/consts/const-points-to-static.stderr @@ -8,7 +8,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/const-points-to-static.rs:5:1 | LL | const TEST: &u8 = &MY_STATIC; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constant accesses static + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a reference pointing to a static variable | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. diff --git a/src/test/ui/consts/issue-63952.stderr b/src/test/ui/consts/issue-63952.stderr index d5ed970fc35..5e85be45b16 100644 --- a/src/test/ui/consts/issue-63952.stderr +++ b/src/test/ui/consts/issue-63952.stderr @@ -8,7 +8,7 @@ LL | | ptr: &42, ... | LL | | .slice LL | | }; - | |__^ invalid slice: total size is bigger than largest supported object + | |__^ type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. diff --git a/src/test/ui/consts/miri_unleashed/const_refers_to_static.stderr b/src/test/ui/consts/miri_unleashed/const_refers_to_static.stderr index 15e13942481..ad777cfe8ea 100644 --- a/src/test/ui/consts/miri_unleashed/const_refers_to_static.stderr +++ b/src/test/ui/consts/miri_unleashed/const_refers_to_static.stderr @@ -48,7 +48,7 @@ LL | | static FOO: AtomicUsize = AtomicUsize::new(0); LL | | unsafe { &*(&FOO as *const _ as *const usize) } LL | | LL | | }; - | |__^ constant accesses static + | |__^ type validation failed: encountered a reference pointing to a static variable | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. @@ -97,7 +97,7 @@ LL | | static FOO: usize = 0; LL | | &FOO LL | | LL | | }; - | |__^ constant accesses static + | |__^ type validation failed: encountered a reference pointing to a static variable | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. From 85e1466232eadd2ec6b9c2ae0aa4030a39fde04f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 6 Mar 2020 11:30:57 +0100 Subject: [PATCH 4/5] Fix typo Co-Authored-By: bjorn3 --- src/librustc/mir/interpret/error.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index 731c3ee0d6a..5869c76345a 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -617,8 +617,8 @@ impl fmt::Debug for InterpError<'_> { } impl InterpError<'_> { - /// Some errors allocate to be created as they contain free-from strings. - /// And sometiems we want to be sure that did not happen as it is a + /// Some errors allocate to be created as they contain free-form strings. + /// And sometimes we want to be sure that did not happen as it is a /// waste of resources. pub fn allocates(&self) -> bool { match self { From ed3014a2b9470a89165f2762ba746ee7736d5590 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 6 Mar 2020 18:14:41 +0100 Subject: [PATCH 5/5] use static strings instead of tcx --- src/librustc/mir/interpret/error.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index 5869c76345a..b46095927b7 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -304,7 +304,7 @@ impl fmt::Debug for InvalidProgramInfo<'_> { } /// Error information for when the program caused Undefined Behavior. -pub enum UndefinedBehaviorInfo<'tcx> { +pub enum UndefinedBehaviorInfo { /// Free-form case. Only for errors that are never caught! Ub(String), /// Free-form case for experimental UB. Only for errors that are never caught! @@ -322,10 +322,10 @@ pub enum UndefinedBehaviorInfo<'tcx> { /// Overflowing inbounds pointer arithmetic. PointerArithOverflow, /// Invalid metadata in a wide pointer (using `str` to avoid allocations). - InvalidMeta(&'tcx str), + InvalidMeta(&'static str), } -impl fmt::Debug for UndefinedBehaviorInfo<'_> { +impl fmt::Debug for UndefinedBehaviorInfo { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use UndefinedBehaviorInfo::*; match self { @@ -358,7 +358,7 @@ pub enum UnsupportedOpInfo<'tcx> { /// When const-prop encounters a situation it does not support, it raises this error. /// This must not allocate for performance reasons (hence `str`, not `String`). - ConstPropUnsupported(&'tcx str), + ConstPropUnsupported(&'static str), // -- Everything below is not categorized yet -- FunctionAbiMismatch(Abi, Abi), @@ -580,7 +580,7 @@ impl fmt::Debug for ResourceExhaustionInfo { pub enum InterpError<'tcx> { /// The program caused undefined behavior. - UndefinedBehavior(UndefinedBehaviorInfo<'tcx>), + UndefinedBehavior(UndefinedBehaviorInfo), /// The program did something the interpreter does not support (some of these *might* be UB /// but the interpreter is not sure). Unsupported(UnsupportedOpInfo<'tcx>),