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 ;
1212use std:: hash:: Hash ;
1313
1414use syntax_pos:: symbol:: Symbol ;
1515use rustc:: ty:: layout:: { self , Size , Align , TyLayout , LayoutOf } ;
16- use rustc:: ty:: { self , TyCtxt } ;
16+ use rustc:: ty;
1717use rustc_data_structures:: fx:: FxHashSet ;
1818use 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
192185impl < ' 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