diff options
| -rw-r--r-- | src/librustc_lint/builtin.rs | 1 | ||||
| -rw-r--r-- | src/librustc_mir/const_eval.rs | 1 | ||||
| -rw-r--r-- | src/librustc_mir/interpret/machine.rs | 3 | ||||
| -rw-r--r-- | src/librustc_mir/interpret/place.rs | 22 | ||||
| -rw-r--r-- | src/librustc_mir/interpret/validity.rs | 21 |
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); } } |
