8
8
// option. This file may not be copied, modified, or distributed
9
9
// except according to those terms.
10
10
11
- use std:: fmt:: { self , Write } ;
11
+ use std:: fmt:: Write ;
12
12
use std:: hash:: Hash ;
13
13
14
14
use syntax_pos:: symbol:: Symbol ;
15
15
use rustc:: ty:: layout:: { self , Size , Align , TyLayout , LayoutOf } ;
16
- use rustc:: ty:: { self , TyCtxt } ;
16
+ use rustc:: ty;
17
17
use rustc_data_structures:: fx:: FxHashSet ;
18
18
use rustc:: mir:: interpret:: {
19
19
Scalar , AllocType , EvalResult , EvalErrorKind
@@ -122,24 +122,17 @@ fn path_format(path: &Vec<PathElem>) -> String {
122
122
out
123
123
}
124
124
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 > {
127
126
/// The `path` may be pushed to, but the part that is present when a function
128
127
/// starts must not be changed! `visit_fields` and `visit_array` rely on
129
128
/// this stack discipline.
130
129
path : Vec < PathElem > ,
131
- ref_tracking : Option < & ' rt mut RefTracking < ' tcx , Tag > > ,
130
+ ref_tracking : Option < & ' rt mut RefTracking < ' tcx , M :: PointerTag > > ,
132
131
const_mode : bool ,
133
- tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
132
+ ecx : & ' rt mut EvalContext < ' a , ' mir , ' tcx , M > ,
134
133
}
135
134
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 > {
143
136
fn push_aggregate_field_path_elem (
144
137
& mut self ,
145
138
layout : TyLayout < ' tcx > ,
@@ -148,7 +141,7 @@ impl<'rt, 'a, 'tcx, Tag> ValidityVisitor<'rt, 'a, 'tcx, Tag> {
148
141
let elem = match layout. ty . sty {
149
142
// generators and closures.
150
143
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) {
152
145
PathElem :: ClosureVar ( upvar. debug_name )
153
146
} else {
154
147
// Sometimes the index is beyond the number of freevars (seen
@@ -190,41 +183,38 @@ impl<'rt, 'a, 'tcx, Tag> ValidityVisitor<'rt, 'a, 'tcx, Tag> {
190
183
}
191
184
192
185
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 >
194
187
{
195
188
type V = OpTy < ' tcx , M :: PointerTag > ;
196
189
197
190
#[ 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
200
193
}
201
194
202
195
#[ inline]
203
196
fn visit_field (
204
197
& mut self ,
205
- ectx : & mut EvalContext < ' a , ' mir , ' tcx , M > ,
206
- val : Self :: V ,
198
+ old_op : OpTy < ' tcx , M :: PointerTag > ,
207
199
field : usize ,
200
+ new_op : OpTy < ' tcx , M :: PointerTag >
208
201
) -> EvalResult < ' tcx > {
209
202
// Remember the old state
210
203
let path_len = self . path . len ( ) ;
211
- let op = self . op ;
212
204
// 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) ?;
216
207
// Undo changes
217
208
self . path . truncate ( path_len) ;
218
- self . op = op;
219
209
Ok ( ( ) )
220
210
}
221
211
222
212
#[ 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 >
225
214
{
215
+ trace ! ( "visit_value: {:?}, {:?}" , * op, op. layout) ;
226
216
// Translate enum discriminant errors to something nicer.
227
- match self . walk_value ( ectx ) {
217
+ match self . walk_value ( op ) {
228
218
Ok ( ( ) ) => Ok ( ( ) ) ,
229
219
Err ( err) => match err. kind {
230
220
EvalErrorKind :: InvalidDiscriminant ( val) =>
@@ -236,10 +226,10 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
236
226
}
237
227
}
238
228
239
- fn visit_primitive ( & mut self , ectx : & mut EvalContext < ' a , ' mir , ' tcx , M > )
229
+ fn visit_primitive ( & mut self , op : OpTy < ' tcx , M :: PointerTag > )
240
230
-> EvalResult < ' tcx >
241
231
{
242
- let value = try_validation ! ( ectx . read_value( self . op) ,
232
+ let value = try_validation ! ( self . ecx . read_value( op) ,
243
233
"uninitialized or unrepresentable data" , self . path) ;
244
234
// Go over all the primitive types
245
235
let ty = value. layout . ty ;
@@ -283,21 +273,21 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
283
273
"undefined address in pointer" , self . path) ;
284
274
let meta = try_validation ! ( value. to_meta( ) ,
285
275
"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 ) ?;
287
277
if layout. is_unsized ( ) {
288
- let tail = ectx . tcx . struct_tail ( layout. ty ) ;
278
+ let tail = self . ecx . tcx . struct_tail ( layout. ty ) ;
289
279
match tail. sty {
290
280
ty:: Dynamic ( ..) => {
291
281
let vtable = try_validation ! ( meta. unwrap( ) . to_ptr( ) ,
292
282
"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) ,
294
284
"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) ,
296
286
"invalid size or align in vtable" , self . path) ;
297
287
// FIXME: More checks for the vtable.
298
288
}
299
289
ty:: Slice ( ..) | ty:: Str => {
300
- try_validation ! ( meta. unwrap( ) . to_usize( & ectx ) ,
290
+ try_validation ! ( meta. unwrap( ) . to_usize( & self . ecx ) ,
301
291
"non-integer slice length in fat pointer" , self . path) ;
302
292
}
303
293
ty:: Foreign ( ..) => {
@@ -308,12 +298,12 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
308
298
}
309
299
}
310
300
// 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) ?
312
302
// for the purpose of validity, consider foreign types to have
313
303
// alignment and size determined by the layout (size will be 0,
314
304
// alignment should take attributes into account).
315
305
. unwrap_or_else ( || layout. size_and_align ( ) ) ;
316
- match ectx . memory . check_align ( ptr, align) {
306
+ match self . ecx . memory . check_align ( ptr, align) {
317
307
Ok ( _) => { } ,
318
308
Err ( err) => {
319
309
error ! ( "{:?} is not aligned to {:?}" , ptr, align) ;
@@ -334,7 +324,7 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
334
324
// Turn ptr into place.
335
325
// `ref_to_mplace` also calls the machine hook for (re)activating the tag,
336
326
// 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) ?;
338
328
// Recursive checking
339
329
if let Some ( ref mut ref_tracking) = self . ref_tracking {
340
330
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>>
343
333
let ptr = try_validation ! ( place. ptr. to_ptr( ) ,
344
334
"integer pointer in non-ZST reference" , self . path) ;
345
335
// 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 ) ;
347
337
if let Some ( AllocType :: Static ( did) ) = alloc_kind {
348
338
// `extern static` cannot be validated as they have no body.
349
339
// FIXME: Statics from other crates are also skipped.
350
340
// They might be checked at a different type, but for now we
351
341
// 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) {
353
343
return Ok ( ( ) ) ;
354
344
}
355
345
}
356
346
// Maintain the invariant that the place we are checking is
357
347
// 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 ) ,
359
349
"dangling (not entirely in bounds) reference" , self . path) ;
360
350
}
361
351
// Check if we have encountered this pointer+layout combination
@@ -379,7 +369,7 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
379
369
let value = value. to_scalar_or_undef ( ) ;
380
370
let ptr = try_validation ! ( value. to_ptr( ) ,
381
371
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) ,
383
373
value, self . path, "a function pointer" ) ;
384
374
// FIXME: Check if the signature matches
385
375
}
@@ -389,21 +379,23 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
389
379
Ok ( ( ) )
390
380
}
391
381
392
- fn visit_uninhabited ( & mut self , _ectx : & mut EvalContext < ' a , ' mir , ' tcx , M > )
382
+ fn visit_uninhabited ( & mut self , _op : OpTy < ' tcx , M :: PointerTag > )
393
383
-> EvalResult < ' tcx >
394
384
{
395
385
validation_failure ! ( "a value of an uninhabited type" , self . path)
396
386
}
397
387
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) ,
402
394
"uninitialized or unrepresentable data" , self . path) ;
403
395
// Determine the allowed range
404
396
let ( lo, hi) = layout. valid_range . clone ( ) . into_inner ( ) ;
405
397
// `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 ( ) ) ;
407
399
assert ! ( hi <= max_hi) ;
408
400
// We could also write `(hi + 1) % (max_hi + 1) == lo` but `max_hi + 1` overflows for `u128`
409
401
if ( lo == 0 && hi == max_hi) || ( hi + 1 == lo) {
@@ -421,10 +413,10 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
421
413
// We can call `check_align` to check non-NULL-ness, but have to also look
422
414
// for function pointers.
423
415
let non_null =
424
- ectx . memory . check_align (
416
+ self . ecx . memory . check_align (
425
417
Scalar :: Ptr ( ptr) , Align :: from_bytes ( 1 , 1 ) . unwrap ( )
426
418
) . is_ok ( ) ||
427
- ectx . memory . get_fn ( ptr) . is_ok ( ) ;
419
+ self . ecx . memory . get_fn ( ptr) . is_ok ( ) ;
428
420
if !non_null {
429
421
// could be NULL
430
422
return validation_failure ! ( "a potentially NULL pointer" , self . path) ;
@@ -444,7 +436,7 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
444
436
}
445
437
}
446
438
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( ) ) ;
448
440
bits
449
441
}
450
442
} ;
@@ -479,13 +471,12 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
479
471
}
480
472
}
481
473
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 >
484
475
{
485
- match self . op . layout . ty . sty {
476
+ match op. layout . ty . sty {
486
477
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) ,
489
480
"uninitialized or non-UTF-8 data in str" , self . path) ;
490
481
}
491
482
ty:: Array ( tys, ..) | ty:: Slice ( tys) if {
@@ -496,17 +487,17 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
496
487
_ => false ,
497
488
}
498
489
} => {
499
- let mplace = if self . op . layout . is_zst ( ) {
490
+ let mplace = if op. layout . is_zst ( ) {
500
491
// it's a ZST, the memory content cannot matter
501
- MPlaceTy :: dangling ( self . op . layout , & ectx )
492
+ MPlaceTy :: dangling ( op. layout , & self . ecx )
502
493
} else {
503
494
// non-ZST array/slice/str cannot be immediate
504
- self . op . to_mem_place ( )
495
+ op. to_mem_place ( )
505
496
} ;
506
497
// This is the length of the array/slice.
507
- let len = mplace. len ( & ectx ) ?;
498
+ let len = mplace. len ( & self . ecx ) ?;
508
499
// 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 ;
510
501
// This is the size in bytes of the whole array.
511
502
let size = ty_size * len;
512
503
@@ -519,7 +510,7 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
519
510
// to reject those pointers, we just do not have the machinery to
520
511
// talk about parts of a pointer.
521
512
// We also accept undef, for consistency with the type-based checks.
522
- match ectx . memory . check_bytes (
513
+ match self . ecx . memory . check_bytes (
523
514
mplace. ptr ,
524
515
size,
525
516
/*allow_ptr_and_undef*/ !self . const_mode ,
@@ -548,7 +539,7 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
548
539
}
549
540
}
550
541
_ => {
551
- self . walk_array ( ectx ) ? // default handler
542
+ self . walk_array ( op ) ? // default handler
552
543
}
553
544
}
554
545
Ok ( ( ) )
@@ -574,14 +565,13 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
574
565
575
566
// Construct a visitor
576
567
let mut visitor = ValidityVisitor {
577
- op,
578
568
path,
579
569
ref_tracking,
580
570
const_mode,
581
- tcx : * self . tcx ,
571
+ ecx : self ,
582
572
} ;
583
573
584
574
// Run it
585
- visitor. visit_value ( self )
575
+ visitor. visit_value ( op )
586
576
}
587
577
}
0 commit comments