about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_lint/builtin.rs1
-rw-r--r--src/librustc_mir/const_eval.rs1
-rw-r--r--src/librustc_mir/interpret/machine.rs3
-rw-r--r--src/librustc_mir/interpret/place.rs22
-rw-r--r--src/librustc_mir/interpret/validity.rs21
5 files changed, 39 insertions, 9 deletions
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 8dd1e2b53cd..d18edf22dc1 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -1564,6 +1564,7 @@ fn validate_const<'a, 'tcx>(
                 op,
                 &mut path,
                 Some(&mut ref_tracking),
+                /* const_mode */ true,
             )?;
         }
         Ok(())
diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs
index 3b1eba51aaf..0c669b9ec31 100644
--- a/src/librustc_mir/const_eval.rs
+++ b/src/librustc_mir/const_eval.rs
@@ -274,6 +274,7 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx>
     type MemoryKinds = !;
 
     const MUT_STATIC_KIND: Option<!> = None; // no mutating of statics allowed
+    const ENFORCE_VALIDITY: bool = false; // for now, we don't
 
     fn find_fn(
         ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs
index 1eb02804095..f90a7efce47 100644
--- a/src/librustc_mir/interpret/machine.rs
+++ b/src/librustc_mir/interpret/machine.rs
@@ -33,6 +33,9 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized {
     /// The memory kind to use for mutated statics -- or None if those are not supported.
     const MUT_STATIC_KIND: Option<Self::MemoryKinds>;
 
+    /// Whether to enforce the validity invariant
+    const ENFORCE_VALIDITY: bool;
+
     /// Called before a basic block terminator is executed.
     /// You can use this to detect endlessly running programs.
     fn before_terminator(ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>) -> EvalResult<'tcx>;
diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs
index f8e1e9e55d5..b75ceb61feb 100644
--- a/src/librustc_mir/interpret/place.rs
+++ b/src/librustc_mir/interpret/place.rs
@@ -567,6 +567,13 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
         dest: PlaceTy<'tcx>,
     ) -> EvalResult<'tcx> {
         trace!("write_value: {:?} <- {:?}", *dest, src_val);
+        // Check that the value actually is okay for that type
+        if M::ENFORCE_VALIDITY {
+            // Something changed somewhere, better make sure it matches the type!
+            let op = OpTy { op: Operand::Immediate(src_val), layout: dest.layout };
+            self.validate_operand(op, &mut vec![], None, /*const_mode*/false)?;
+        }
+
         // See if we can avoid an allocation. This is the counterpart to `try_read_value`,
         // but not factored as a separate function.
         let mplace = match dest.place {
@@ -588,7 +595,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
         self.write_value_to_mplace(src_val, dest)
     }
 
-    /// Write a value to memory
+    /// Write a value to memory. This does NOT do validation, so you better had already
+    /// done that before calling this!
     fn write_value_to_mplace(
         &mut self,
         value: Value,
@@ -652,12 +660,18 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
         };
         // Slow path, this does not fit into an immediate. Just memcpy.
         trace!("copy_op: {:?} <- {:?}", *dest, *src);
-        let (dest_ptr, dest_align) = self.force_allocation(dest)?.to_scalar_ptr_align();
+        let dest = self.force_allocation(dest)?;
+        let (dest_ptr, dest_align) = dest.to_scalar_ptr_align();
         self.memory.copy(
             src_ptr, src_align,
             dest_ptr, dest_align,
             src.layout.size, false
-        )
+        )?;
+        if M::ENFORCE_VALIDITY {
+            // Something changed somewhere, better make sure it matches the type!
+            self.validate_operand(dest.into(), &mut vec![], None, /*const_mode*/false)?;
+        }
+        Ok(())
     }
 
     /// Make sure that a place is in memory, and return where it is.
@@ -680,6 +694,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
                         // that has different alignment than the outer field.
                         let local_layout = self.layout_of_local(frame, local)?;
                         let ptr = self.allocate(local_layout, MemoryKind::Stack)?;
+                        // We don't have to validate as we can assume the local
+                        // was already valid for its type.
                         self.write_value_to_mplace(value, ptr)?;
                         let mplace = ptr.mplace;
                         // Update the local
diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs
index a174645b7ef..5c8aeb2d82a 100644
--- a/src/librustc_mir/interpret/validity.rs
+++ b/src/librustc_mir/interpret/validity.rs
@@ -147,6 +147,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
         size: Size,
         path: &Vec<PathElem>,
         ty: Ty,
+        const_mode: bool,
     ) -> EvalResult<'tcx> {
         trace!("validate scalar by type: {:#?}, {:#?}, {}", value, size, ty);
 
@@ -160,12 +161,12 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
                 try_validation!(value.to_char(),
                     scalar_format(value), path, "a valid unicode codepoint");
             },
-            ty::Float(_) | ty::Int(_) | ty::Uint(_) => {
-                // Must be scalar bits
+            ty::Float(_) | ty::Int(_) | ty::Uint(_) if const_mode => {
+                // Integers/floats in CTFE: Must be scalar bits
                 try_validation!(value.to_bits(size),
                     scalar_format(value), path, "initialized plain bits");
             }
-            ty::RawPtr(_) => {
+            ty::Float(_) | ty::Int(_) | ty::Uint(_) | ty::RawPtr(_) => {
                 // Anything but undef goes
                 try_validation!(value.not_undef(),
                     scalar_format(value), path, "a raw pointer");
@@ -303,6 +304,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
         dest: OpTy<'tcx>,
         path: &mut Vec<PathElem>,
         mut ref_tracking: Option<&mut RefTracking<'tcx>>,
+        const_mode: bool,
     ) -> EvalResult<'tcx> {
         trace!("validate_operand: {:?}, {:#?}", *dest, dest.layout);
 
@@ -387,7 +389,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
                             value.to_scalar_or_undef(),
                             dest.layout.size,
                             &path,
-                            dest.layout.ty
+                            dest.layout.ty,
+                            const_mode,
                         )?;
                         // Recursively check *safe* references
                         if dest.layout.ty.builtin_deref(true).is_some() &&
@@ -506,7 +509,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
                             self.validate_operand(
                                 field.into(),
                                 path,
-                                ref_tracking.as_mut().map(|r| &mut **r)
+                                ref_tracking.as_mut().map(|r| &mut **r),
+                                const_mode,
                             )?;
                             path.truncate(path_len);
                         }
@@ -517,7 +521,12 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
                 for i in 0..offsets.len() {
                     let field = self.operand_field(dest, i as u64)?;
                     path.push(self.aggregate_field_path_elem(dest.layout.ty, variant, i));
-                    self.validate_operand(field, path, ref_tracking.as_mut().map(|r| &mut **r))?;
+                    self.validate_operand(
+                        field,
+                        path,
+                        ref_tracking.as_mut().map(|r| &mut **r),
+                        const_mode,
+                    )?;
                     path.truncate(path_len);
                 }
             }