Skip to content

Commit 9d293d1

Browse files
committed
add machine option to validate things on every copy
1 parent 622bc39 commit 9d293d1

File tree

5 files changed

+39
-9
lines changed

5 files changed

+39
-9
lines changed

src/librustc_lint/builtin.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1621,6 +1621,7 @@ fn validate_const<'a, 'tcx>(
16211621
op,
16221622
&mut path,
16231623
Some(&mut ref_tracking),
1624+
/* const_mode */ true,
16241625
)?;
16251626
}
16261627
Ok(())

src/librustc_mir/const_eval.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,7 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx>
277277
type MemoryKinds = !;
278278

279279
const MUT_STATIC_KIND: Option<!> = None; // no mutating of statics allowed
280+
const ENFORCE_VALIDITY: bool = false; // for now, we don't
280281

281282
fn find_fn(
282283
ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,

src/librustc_mir/interpret/machine.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized {
3333
/// The memory kind to use for mutated statics -- or None if those are not supported.
3434
const MUT_STATIC_KIND: Option<Self::MemoryKinds>;
3535

36+
/// Whether to enforce the validity invariant
37+
const ENFORCE_VALIDITY: bool;
38+
3639
/// Called before a basic block terminator is executed.
3740
/// You can use this to detect endlessly running programs.
3841
fn before_terminator(ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>) -> EvalResult<'tcx>;

src/librustc_mir/interpret/place.rs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,13 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
567567
dest: PlaceTy<'tcx>,
568568
) -> EvalResult<'tcx> {
569569
trace!("write_value: {:?} <- {:?}", *dest, src_val);
570+
// Check that the value actually is okay for that type
571+
if M::ENFORCE_VALIDITY {
572+
// Something changed somewhere, better make sure it matches the type!
573+
let op = OpTy { op: Operand::Immediate(src_val), layout: dest.layout };
574+
self.validate_operand(op, &mut vec![], None, /*const_mode*/false)?;
575+
}
576+
570577
// See if we can avoid an allocation. This is the counterpart to `try_read_value`,
571578
// but not factored as a separate function.
572579
let mplace = match dest.place {
@@ -588,7 +595,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
588595
self.write_value_to_mplace(src_val, dest)
589596
}
590597

591-
/// Write a value to memory
598+
/// Write a value to memory. This does NOT do validation, so you better had already
599+
/// done that before calling this!
592600
fn write_value_to_mplace(
593601
&mut self,
594602
value: Value,
@@ -652,12 +660,18 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
652660
};
653661
// Slow path, this does not fit into an immediate. Just memcpy.
654662
trace!("copy_op: {:?} <- {:?}", *dest, *src);
655-
let (dest_ptr, dest_align) = self.force_allocation(dest)?.to_scalar_ptr_align();
663+
let dest = self.force_allocation(dest)?;
664+
let (dest_ptr, dest_align) = dest.to_scalar_ptr_align();
656665
self.memory.copy(
657666
src_ptr, src_align,
658667
dest_ptr, dest_align,
659668
src.layout.size, false
660-
)
669+
)?;
670+
if M::ENFORCE_VALIDITY {
671+
// Something changed somewhere, better make sure it matches the type!
672+
self.validate_operand(dest.into(), &mut vec![], None, /*const_mode*/false)?;
673+
}
674+
Ok(())
661675
}
662676

663677
/// 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>
680694
// that has different alignment than the outer field.
681695
let local_layout = self.layout_of_local(frame, local)?;
682696
let ptr = self.allocate(local_layout, MemoryKind::Stack)?;
697+
// We don't have to validate as we can assume the local
698+
// was already valid for its type.
683699
self.write_value_to_mplace(value, ptr)?;
684700
let mplace = ptr.mplace;
685701
// Update the local

src/librustc_mir/interpret/validity.rs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
147147
size: Size,
148148
path: &Vec<PathElem>,
149149
ty: Ty,
150+
const_mode: bool,
150151
) -> EvalResult<'tcx> {
151152
trace!("validate scalar by type: {:#?}, {:#?}, {}", value, size, ty);
152153

@@ -160,12 +161,12 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
160161
try_validation!(value.to_char(),
161162
scalar_format(value), path, "a valid unicode codepoint");
162163
},
163-
ty::Float(_) | ty::Int(_) | ty::Uint(_) => {
164-
// Must be scalar bits
164+
ty::Float(_) | ty::Int(_) | ty::Uint(_) if const_mode => {
165+
// Integers/floats in CTFE: Must be scalar bits
165166
try_validation!(value.to_bits(size),
166167
scalar_format(value), path, "initialized plain bits");
167168
}
168-
ty::RawPtr(_) => {
169+
ty::Float(_) | ty::Int(_) | ty::Uint(_) | ty::RawPtr(_) => {
169170
// Anything but undef goes
170171
try_validation!(value.not_undef(),
171172
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>
303304
dest: OpTy<'tcx>,
304305
path: &mut Vec<PathElem>,
305306
mut ref_tracking: Option<&mut RefTracking<'tcx>>,
307+
const_mode: bool,
306308
) -> EvalResult<'tcx> {
307309
trace!("validate_operand: {:?}, {:#?}", *dest, dest.layout);
308310

@@ -387,7 +389,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
387389
value.to_scalar_or_undef(),
388390
dest.layout.size,
389391
&path,
390-
dest.layout.ty
392+
dest.layout.ty,
393+
const_mode,
391394
)?;
392395
// Recursively check *safe* references
393396
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>
506509
self.validate_operand(
507510
field.into(),
508511
path,
509-
ref_tracking.as_mut().map(|r| &mut **r)
512+
ref_tracking.as_mut().map(|r| &mut **r),
513+
const_mode,
510514
)?;
511515
path.truncate(path_len);
512516
}
@@ -517,7 +521,12 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
517521
for i in 0..offsets.len() {
518522
let field = self.operand_field(dest, i as u64)?;
519523
path.push(self.aggregate_field_path_elem(dest.layout.ty, variant, i));
520-
self.validate_operand(field, path, ref_tracking.as_mut().map(|r| &mut **r))?;
524+
self.validate_operand(
525+
field,
526+
path,
527+
ref_tracking.as_mut().map(|r| &mut **r),
528+
const_mode,
529+
)?;
521530
path.truncate(path_len);
522531
}
523532
}

0 commit comments

Comments
 (0)