diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index c303d2a1e67caa226c444f0138631ea1a80b7e42..5ba15f4bb99af3a557f63210635b776dac8c71a7 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -20,7 +20,7 @@ }; use super::{ - OpTy, MPlaceTy, Machine, EvalContext, ValueVisitor + OpTy, MPlaceTy, ImmTy, Machine, EvalContext, ValueVisitor }; macro_rules! validation_failure { @@ -213,7 +213,7 @@ fn visit_field( fn visit_value(&mut self, op: OpTy<'tcx, M::PointerTag>) -> EvalResult<'tcx> { trace!("visit_value: {:?}, {:?}", *op, op.layout); - // Translate enum discriminant errors to something nicer. + // Translate some possible errors to something nicer. match self.walk_value(op) { Ok(()) => Ok(()), Err(err) => match err.kind { @@ -221,16 +221,17 @@ fn visit_value(&mut self, op: OpTy<'tcx, M::PointerTag>) -> EvalResult<'tcx> validation_failure!( val, self.path, "a valid enum discriminant" ), + EvalErrorKind::ReadPointerAsBytes => + validation_failure!( + "a pointer", self.path, "plain bytes" + ), _ => Err(err), } } } - fn visit_primitive(&mut self, op: OpTy<'tcx, M::PointerTag>) - -> EvalResult<'tcx> + fn visit_primitive(&mut self, value: ImmTy<'tcx, M::PointerTag>) -> EvalResult<'tcx> { - let value = try_validation!(self.ecx.read_immediate(op), - "uninitialized or unrepresentable data", self.path); // Go over all the primitive types let ty = value.layout.ty; match ty.sty { @@ -379,8 +380,7 @@ fn visit_primitive(&mut self, op: OpTy<'tcx, M::PointerTag>) Ok(()) } - fn visit_uninhabited(&mut self, _op: OpTy<'tcx, M::PointerTag>) - -> EvalResult<'tcx> + fn visit_uninhabited(&mut self) -> EvalResult<'tcx> { validation_failure!("a value of an uninhabited type", self.path) } @@ -390,8 +390,7 @@ fn visit_scalar( op: OpTy<'tcx, M::PointerTag>, layout: &layout::Scalar, ) -> EvalResult<'tcx> { - let value = try_validation!(self.ecx.read_scalar(op), - "uninitialized or unrepresentable data", self.path); + let value = self.ecx.read_scalar(op)?; // Determine the allowed range let (lo, hi) = layout.valid_range.clone().into_inner(); // `max_hi` is as big as the size fits diff --git a/src/librustc_mir/interpret/visitor.rs b/src/librustc_mir/interpret/visitor.rs index 7ae747a735790381f378bd5b68d11ad1fc106224..3211601400a701d6accddb20bf04639ea7285564 100644 --- a/src/librustc_mir/interpret/visitor.rs +++ b/src/librustc_mir/interpret/visitor.rs @@ -8,7 +8,7 @@ }; use super::{ - Machine, EvalContext, MPlaceTy, PlaceTy, OpTy, + Machine, EvalContext, MPlaceTy, PlaceTy, OpTy, ImmTy, }; // A thing that we can project into, and that has a layout. @@ -205,9 +205,11 @@ fn visit_field( /// Called whenever we reach a value with uninhabited layout. /// Recursing to fields will continue after this! #[inline(always)] - fn visit_uninhabited(&mut self, _v: Self::V) -> EvalResult<'tcx> + fn visit_uninhabited(&mut self) -> EvalResult<'tcx> { Ok(()) } /// Called whenever we reach a value with scalar layout. + /// We do NOT provide a `ScalarMaybeUndef` here to avoid accessing memory + /// if the visitor is not even interested in scalars. /// Recursing to fields will continue after this! #[inline(always)] fn visit_scalar(&mut self, _v: Self::V, _layout: &layout::Scalar) -> EvalResult<'tcx> @@ -215,7 +217,7 @@ fn visit_scalar(&mut self, _v: Self::V, _layout: &layout::Scalar) -> EvalResult< /// Called whenever we reach a value of primitive type. There can be no recursion /// below such a value. #[inline(always)] - fn visit_primitive(&mut self, _v: Self::V) -> EvalResult<'tcx> + fn visit_primitive(&mut self, _val: ImmTy<'tcx, M::PointerTag>) -> EvalResult<'tcx> { Ok(()) } // Default recursors. Not meant to be overloaded. @@ -275,7 +277,7 @@ fn walk_value(&mut self, v: Self::V) -> EvalResult<'tcx> // MyNewtype and then the scalar in there). match v.layout().abi { layout::Abi::Uninhabited => { - self.visit_uninhabited(v)?; + self.visit_uninhabited()?; } layout::Abi::Scalar(ref layout) => { self.visit_scalar(v, layout)?; @@ -295,7 +297,9 @@ fn walk_value(&mut self, v: Self::V) -> EvalResult<'tcx> _ => v.layout().ty.builtin_deref(true).is_some(), }; if primitive { - return self.visit_primitive(v); + let op = v.to_op(self.ecx())?; + let val = self.ecx().read_immediate(op)?; + return self.visit_primitive(val); } // Proceed into the fields. diff --git a/src/test/ui/consts/const-eval/ub-ref.stderr b/src/test/ui/consts/const-eval/ub-ref.stderr index 359d1abb5008e4d726b0dce18ec8620f11b1a8b9..c3f5f4a26f55594cbc6b2545df8774de73d588ab 100644 --- a/src/test/ui/consts/const-eval/ub-ref.stderr +++ b/src/test/ui/consts/const-eval/ub-ref.stderr @@ -26,7 +26,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref.rs:25:1 | LL | const REF_AS_USIZE_SLICE: &[usize] = &[unsafe { mem::transmute(&0) }]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ a raw memory access tried to access part of a pointer value as raw bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer at ., but expected plain bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior