Skip to content

Commit 9e32b6f

Browse files
committed
finally this actually looks like a visitor
1 parent 19c3a17 commit 9e32b6f

File tree

2 files changed

+118
-132
lines changed

2 files changed

+118
-132
lines changed

src/librustc_mir/interpret/validity.rs

Lines changed: 55 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use std::fmt::{self, Write};
11+
use std::fmt::Write;
1212
use std::hash::Hash;
1313

1414
use syntax_pos::symbol::Symbol;
1515
use rustc::ty::layout::{self, Size, Align, TyLayout, LayoutOf};
16-
use rustc::ty::{self, TyCtxt};
16+
use rustc::ty;
1717
use rustc_data_structures::fx::FxHashSet;
1818
use rustc::mir::interpret::{
1919
Scalar, AllocType, EvalResult, EvalErrorKind
@@ -122,24 +122,17 @@ fn path_format(path: &Vec<PathElem>) -> String {
122122
out
123123
}
124124

125-
struct ValidityVisitor<'rt, 'a, 'tcx: 'a+'rt, Tag: 'static> {
126-
op: OpTy<'tcx, Tag>,
125+
struct ValidityVisitor<'rt, 'a: 'rt, 'mir: 'rt, 'tcx: 'a+'rt+'mir, M: Machine<'a, 'mir, 'tcx>+'rt> {
127126
/// The `path` may be pushed to, but the part that is present when a function
128127
/// starts must not be changed! `visit_fields` and `visit_array` rely on
129128
/// this stack discipline.
130129
path: Vec<PathElem>,
131-
ref_tracking: Option<&'rt mut RefTracking<'tcx, Tag>>,
130+
ref_tracking: Option<&'rt mut RefTracking<'tcx, M::PointerTag>>,
132131
const_mode: bool,
133-
tcx: TyCtxt<'a, 'tcx, 'tcx>,
132+
ecx: &'rt mut EvalContext<'a, 'mir, 'tcx, M>,
134133
}
135134

136-
impl<Tag: fmt::Debug> fmt::Debug for ValidityVisitor<'_, '_, '_, Tag> {
137-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
138-
write!(f, "{:?}, {:?}", *self.op, self.op.layout.ty)
139-
}
140-
}
141-
142-
impl<'rt, 'a, 'tcx, Tag> ValidityVisitor<'rt, 'a, 'tcx, Tag> {
135+
impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> ValidityVisitor<'rt, 'a, 'mir, 'tcx, M> {
143136
fn push_aggregate_field_path_elem(
144137
&mut self,
145138
layout: TyLayout<'tcx>,
@@ -148,7 +141,7 @@ impl<'rt, 'a, 'tcx, Tag> ValidityVisitor<'rt, 'a, 'tcx, Tag> {
148141
let elem = match layout.ty.sty {
149142
// generators and closures.
150143
ty::Closure(def_id, _) | ty::Generator(def_id, _, _) => {
151-
if let Some(upvar) = self.tcx.optimized_mir(def_id).upvar_decls.get(field) {
144+
if let Some(upvar) = self.ecx.tcx.optimized_mir(def_id).upvar_decls.get(field) {
152145
PathElem::ClosureVar(upvar.debug_name)
153146
} else {
154147
// Sometimes the index is beyond the number of freevars (seen
@@ -190,41 +183,38 @@ impl<'rt, 'a, 'tcx, Tag> ValidityVisitor<'rt, 'a, 'tcx, Tag> {
190183
}
191184

192185
impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
193-
ValueVisitor<'a, 'mir, 'tcx, M> for ValidityVisitor<'rt, 'a, 'tcx, M::PointerTag>
186+
ValueVisitor<'a, 'mir, 'tcx, M> for ValidityVisitor<'rt, 'a, 'mir, 'tcx, M>
194187
{
195188
type V = OpTy<'tcx, M::PointerTag>;
196189

197190
#[inline(always)]
198-
fn value(&self) -> &OpTy<'tcx, M::PointerTag> {
199-
&self.op
191+
fn ecx(&mut self) -> &mut EvalContext<'a, 'mir, 'tcx, M> {
192+
&mut self.ecx
200193
}
201194

202195
#[inline]
203196
fn visit_field(
204197
&mut self,
205-
ectx: &mut EvalContext<'a, 'mir, 'tcx, M>,
206-
val: Self::V,
198+
old_op: OpTy<'tcx, M::PointerTag>,
207199
field: usize,
200+
new_op: OpTy<'tcx, M::PointerTag>
208201
) -> EvalResult<'tcx> {
209202
// Remember the old state
210203
let path_len = self.path.len();
211-
let op = self.op;
212204
// Perform operation
213-
self.push_aggregate_field_path_elem(op.layout, field);
214-
self.op = val;
215-
self.visit_value(ectx)?;
205+
self.push_aggregate_field_path_elem(old_op.layout, field);
206+
self.visit_value(new_op)?;
216207
// Undo changes
217208
self.path.truncate(path_len);
218-
self.op = op;
219209
Ok(())
220210
}
221211

222212
#[inline]
223-
fn visit_value(&mut self, ectx: &mut EvalContext<'a, 'mir, 'tcx, M>)
224-
-> EvalResult<'tcx>
213+
fn visit_value(&mut self, op: OpTy<'tcx, M::PointerTag>) -> EvalResult<'tcx>
225214
{
215+
trace!("visit_value: {:?}, {:?}", *op, op.layout);
226216
// Translate enum discriminant errors to something nicer.
227-
match self.walk_value(ectx) {
217+
match self.walk_value(op) {
228218
Ok(()) => Ok(()),
229219
Err(err) => match err.kind {
230220
EvalErrorKind::InvalidDiscriminant(val) =>
@@ -236,10 +226,10 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
236226
}
237227
}
238228

239-
fn visit_primitive(&mut self, ectx: &mut EvalContext<'a, 'mir, 'tcx, M>)
229+
fn visit_primitive(&mut self, op: OpTy<'tcx, M::PointerTag>)
240230
-> EvalResult<'tcx>
241231
{
242-
let value = try_validation!(ectx.read_value(self.op),
232+
let value = try_validation!(self.ecx.read_value(op),
243233
"uninitialized or unrepresentable data", self.path);
244234
// Go over all the primitive types
245235
let ty = value.layout.ty;
@@ -283,21 +273,21 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
283273
"undefined address in pointer", self.path);
284274
let meta = try_validation!(value.to_meta(),
285275
"uninitialized data in fat pointer metadata", self.path);
286-
let layout = ectx.layout_of(value.layout.ty.builtin_deref(true).unwrap().ty)?;
276+
let layout = self.ecx.layout_of(value.layout.ty.builtin_deref(true).unwrap().ty)?;
287277
if layout.is_unsized() {
288-
let tail = ectx.tcx.struct_tail(layout.ty);
278+
let tail = self.ecx.tcx.struct_tail(layout.ty);
289279
match tail.sty {
290280
ty::Dynamic(..) => {
291281
let vtable = try_validation!(meta.unwrap().to_ptr(),
292282
"non-pointer vtable in fat pointer", self.path);
293-
try_validation!(ectx.read_drop_type_from_vtable(vtable),
283+
try_validation!(self.ecx.read_drop_type_from_vtable(vtable),
294284
"invalid drop fn in vtable", self.path);
295-
try_validation!(ectx.read_size_and_align_from_vtable(vtable),
285+
try_validation!(self.ecx.read_size_and_align_from_vtable(vtable),
296286
"invalid size or align in vtable", self.path);
297287
// FIXME: More checks for the vtable.
298288
}
299289
ty::Slice(..) | ty::Str => {
300-
try_validation!(meta.unwrap().to_usize(&ectx),
290+
try_validation!(meta.unwrap().to_usize(&self.ecx),
301291
"non-integer slice length in fat pointer", self.path);
302292
}
303293
ty::Foreign(..) => {
@@ -308,12 +298,12 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
308298
}
309299
}
310300
// Make sure this is non-NULL and aligned
311-
let (size, align) = ectx.size_and_align_of(meta, layout)?
301+
let (size, align) = self.ecx.size_and_align_of(meta, layout)?
312302
// for the purpose of validity, consider foreign types to have
313303
// alignment and size determined by the layout (size will be 0,
314304
// alignment should take attributes into account).
315305
.unwrap_or_else(|| layout.size_and_align());
316-
match ectx.memory.check_align(ptr, align) {
306+
match self.ecx.memory.check_align(ptr, align) {
317307
Ok(_) => {},
318308
Err(err) => {
319309
error!("{:?} is not aligned to {:?}", ptr, align);
@@ -334,7 +324,7 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
334324
// Turn ptr into place.
335325
// `ref_to_mplace` also calls the machine hook for (re)activating the tag,
336326
// which in turn will (in full miri) check if the pointer is dereferencable.
337-
let place = ectx.ref_to_mplace(value)?;
327+
let place = self.ecx.ref_to_mplace(value)?;
338328
// Recursive checking
339329
if let Some(ref mut ref_tracking) = self.ref_tracking {
340330
assert!(self.const_mode, "We should only do recursie checking in const mode");
@@ -343,19 +333,19 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
343333
let ptr = try_validation!(place.ptr.to_ptr(),
344334
"integer pointer in non-ZST reference", self.path);
345335
// Skip validation entirely for some external statics
346-
let alloc_kind = ectx.tcx.alloc_map.lock().get(ptr.alloc_id);
336+
let alloc_kind = self.ecx.tcx.alloc_map.lock().get(ptr.alloc_id);
347337
if let Some(AllocType::Static(did)) = alloc_kind {
348338
// `extern static` cannot be validated as they have no body.
349339
// FIXME: Statics from other crates are also skipped.
350340
// They might be checked at a different type, but for now we
351341
// want to avoid recursing too deeply. This is not sound!
352-
if !did.is_local() || ectx.tcx.is_foreign_item(did) {
342+
if !did.is_local() || self.ecx.tcx.is_foreign_item(did) {
353343
return Ok(());
354344
}
355345
}
356346
// Maintain the invariant that the place we are checking is
357347
// already verified to be in-bounds.
358-
try_validation!(ectx.memory.check_bounds(ptr, size, false),
348+
try_validation!(self.ecx.memory.check_bounds(ptr, size, false),
359349
"dangling (not entirely in bounds) reference", self.path);
360350
}
361351
// Check if we have encountered this pointer+layout combination
@@ -379,7 +369,7 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
379369
let value = value.to_scalar_or_undef();
380370
let ptr = try_validation!(value.to_ptr(),
381371
value, self.path, "a pointer");
382-
let _fn = try_validation!(ectx.memory.get_fn(ptr),
372+
let _fn = try_validation!(self.ecx.memory.get_fn(ptr),
383373
value, self.path, "a function pointer");
384374
// FIXME: Check if the signature matches
385375
}
@@ -389,21 +379,23 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
389379
Ok(())
390380
}
391381

392-
fn visit_uninhabited(&mut self, _ectx: &mut EvalContext<'a, 'mir, 'tcx, M>)
382+
fn visit_uninhabited(&mut self, _op: OpTy<'tcx, M::PointerTag>)
393383
-> EvalResult<'tcx>
394384
{
395385
validation_failure!("a value of an uninhabited type", self.path)
396386
}
397387

398-
fn visit_scalar(&mut self, ectx: &mut EvalContext<'a, 'mir, 'tcx, M>, layout: &layout::Scalar)
399-
-> EvalResult<'tcx>
400-
{
401-
let value = try_validation!(ectx.read_scalar(self.op),
388+
fn visit_scalar(
389+
&mut self,
390+
op: OpTy<'tcx, M::PointerTag>,
391+
layout: &layout::Scalar,
392+
) -> EvalResult<'tcx> {
393+
let value = try_validation!(self.ecx.read_scalar(op),
402394
"uninitialized or unrepresentable data", self.path);
403395
// Determine the allowed range
404396
let (lo, hi) = layout.valid_range.clone().into_inner();
405397
// `max_hi` is as big as the size fits
406-
let max_hi = u128::max_value() >> (128 - self.op.layout.size.bits());
398+
let max_hi = u128::max_value() >> (128 - op.layout.size.bits());
407399
assert!(hi <= max_hi);
408400
// We could also write `(hi + 1) % (max_hi + 1) == lo` but `max_hi + 1` overflows for `u128`
409401
if (lo == 0 && hi == max_hi) || (hi + 1 == lo) {
@@ -421,10 +413,10 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
421413
// We can call `check_align` to check non-NULL-ness, but have to also look
422414
// for function pointers.
423415
let non_null =
424-
ectx.memory.check_align(
416+
self.ecx.memory.check_align(
425417
Scalar::Ptr(ptr), Align::from_bytes(1, 1).unwrap()
426418
).is_ok() ||
427-
ectx.memory.get_fn(ptr).is_ok();
419+
self.ecx.memory.get_fn(ptr).is_ok();
428420
if !non_null {
429421
// could be NULL
430422
return validation_failure!("a potentially NULL pointer", self.path);
@@ -444,7 +436,7 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
444436
}
445437
}
446438
Scalar::Bits { bits, size } => {
447-
assert_eq!(size as u64, self.op.layout.size.bytes());
439+
assert_eq!(size as u64, op.layout.size.bytes());
448440
bits
449441
}
450442
};
@@ -479,13 +471,12 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
479471
}
480472
}
481473

482-
fn visit_array(&mut self, ectx: &mut EvalContext<'a, 'mir, 'tcx, M>)
483-
-> EvalResult<'tcx>
474+
fn visit_array(&mut self, op: OpTy<'tcx, M::PointerTag>) -> EvalResult<'tcx>
484475
{
485-
match self.op.layout.ty.sty {
476+
match op.layout.ty.sty {
486477
ty::Str => {
487-
let mplace = self.op.to_mem_place(); // strings are never immediate
488-
try_validation!(ectx.read_str(mplace),
478+
let mplace = op.to_mem_place(); // strings are never immediate
479+
try_validation!(self.ecx.read_str(mplace),
489480
"uninitialized or non-UTF-8 data in str", self.path);
490481
}
491482
ty::Array(tys, ..) | ty::Slice(tys) if {
@@ -496,17 +487,17 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
496487
_ => false,
497488
}
498489
} => {
499-
let mplace = if self.op.layout.is_zst() {
490+
let mplace = if op.layout.is_zst() {
500491
// it's a ZST, the memory content cannot matter
501-
MPlaceTy::dangling(self.op.layout, &ectx)
492+
MPlaceTy::dangling(op.layout, &self.ecx)
502493
} else {
503494
// non-ZST array/slice/str cannot be immediate
504-
self.op.to_mem_place()
495+
op.to_mem_place()
505496
};
506497
// This is the length of the array/slice.
507-
let len = mplace.len(&ectx)?;
498+
let len = mplace.len(&self.ecx)?;
508499
// This is the element type size.
509-
let ty_size = ectx.layout_of(tys)?.size;
500+
let ty_size = self.ecx.layout_of(tys)?.size;
510501
// This is the size in bytes of the whole array.
511502
let size = ty_size * len;
512503

@@ -519,7 +510,7 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
519510
// to reject those pointers, we just do not have the machinery to
520511
// talk about parts of a pointer.
521512
// We also accept undef, for consistency with the type-based checks.
522-
match ectx.memory.check_bytes(
513+
match self.ecx.memory.check_bytes(
523514
mplace.ptr,
524515
size,
525516
/*allow_ptr_and_undef*/!self.const_mode,
@@ -548,7 +539,7 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
548539
}
549540
}
550541
_ => {
551-
self.walk_array(ectx)? // default handler
542+
self.walk_array(op)? // default handler
552543
}
553544
}
554545
Ok(())
@@ -574,14 +565,13 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
574565

575566
// Construct a visitor
576567
let mut visitor = ValidityVisitor {
577-
op,
578568
path,
579569
ref_tracking,
580570
const_mode,
581-
tcx: *self.tcx,
571+
ecx: self,
582572
};
583573

584574
// Run it
585-
visitor.visit_value(self)
575+
visitor.visit_value(op)
586576
}
587577
}

0 commit comments

Comments
 (0)