@@ -78,6 +78,7 @@ pub enum PathElem {
78
78
TupleElem ( usize ) ,
79
79
Deref ,
80
80
Tag ,
81
+ DynDowncast ,
81
82
}
82
83
83
84
/// State for tracking recursive validation of references
@@ -97,75 +98,30 @@ impl<'tcx, Tag: Copy+Eq+Hash> RefTracking<'tcx, Tag> {
97
98
}
98
99
}
99
100
100
- // Adding a Deref and making a copy of the path to be put into the queue
101
- // always go together. This one does it with only new allocation.
102
- fn path_clone_and_deref ( path : & Vec < PathElem > ) -> Vec < PathElem > {
103
- let mut new_path = Vec :: with_capacity ( path. len ( ) +1 ) ;
104
- new_path. clone_from ( path) ;
105
- new_path. push ( PathElem :: Deref ) ;
106
- new_path
107
- }
108
-
109
101
/// Format a path
110
102
fn path_format ( path : & Vec < PathElem > ) -> String {
111
103
use self :: PathElem :: * ;
112
104
113
105
let mut out = String :: new ( ) ;
114
106
for elem in path. iter ( ) {
115
107
match elem {
116
- Field ( name) => write ! ( out, ".{}" , name) . unwrap ( ) ,
117
- ClosureVar ( name) => write ! ( out, ".<closure-var({})>" , name) . unwrap ( ) ,
118
- TupleElem ( idx) => write ! ( out, ".{}" , idx) . unwrap ( ) ,
119
- ArrayElem ( idx) => write ! ( out, "[{}]" , idx) . unwrap ( ) ,
108
+ Field ( name) => write ! ( out, ".{}" , name) ,
109
+ ClosureVar ( name) => write ! ( out, ".<closure-var({})>" , name) ,
110
+ TupleElem ( idx) => write ! ( out, ".{}" , idx) ,
111
+ ArrayElem ( idx) => write ! ( out, "[{}]" , idx) ,
120
112
Deref =>
121
113
// This does not match Rust syntax, but it is more readable for long paths -- and
122
114
// some of the other items here also are not Rust syntax. Actually we can't
123
115
// even use the usual syntax because we are just showing the projections,
124
116
// not the root.
125
- write ! ( out, ".<deref>" ) . unwrap ( ) ,
126
- Tag => write ! ( out, ".<enum-tag>" ) . unwrap ( ) ,
127
- }
117
+ write ! ( out, ".<deref>" ) ,
118
+ Tag => write ! ( out, ".<enum-tag>" ) ,
119
+ DynDowncast => write ! ( out, ".<dyn-downcast>" ) ,
120
+ } . unwrap ( )
128
121
}
129
122
out
130
123
}
131
124
132
- fn aggregate_field_path_elem < ' a , ' tcx > (
133
- layout : TyLayout < ' tcx > ,
134
- field : usize ,
135
- tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
136
- ) -> PathElem {
137
- match layout. ty . sty {
138
- // generators and closures.
139
- ty:: Closure ( def_id, _) | ty:: Generator ( def_id, _, _) => {
140
- if let Some ( upvar) = tcx. optimized_mir ( def_id) . upvar_decls . get ( field) {
141
- PathElem :: ClosureVar ( upvar. debug_name )
142
- } else {
143
- // Sometimes the index is beyond the number of freevars (seen
144
- // for a generator).
145
- PathElem :: ClosureVar ( Symbol :: intern ( & field. to_string ( ) ) )
146
- }
147
- }
148
-
149
- // tuples
150
- ty:: Tuple ( _) => PathElem :: TupleElem ( field) ,
151
-
152
- // enums
153
- ty:: Adt ( def, ..) if def. is_enum ( ) => {
154
- let variant = match layout. variants {
155
- layout:: Variants :: Single { index } => & def. variants [ index] ,
156
- _ => bug ! ( "aggregate_field_path_elem: got enum but not in a specific variant" ) ,
157
- } ;
158
- PathElem :: Field ( variant. fields [ field] . ident . name )
159
- }
160
-
161
- // other ADTs
162
- ty:: Adt ( def, _) => PathElem :: Field ( def. non_enum_variant ( ) . fields [ field] . ident . name ) ,
163
-
164
- // nothing else has an aggregate layout
165
- _ => bug ! ( "aggregate_field_path_elem: got non-aggregate type {:?}" , layout. ty) ,
166
- }
167
- }
168
-
169
125
fn scalar_format < Tag > ( value : ScalarMaybeUndef < Tag > ) -> String {
170
126
match value {
171
127
ScalarMaybeUndef :: Undef =>
@@ -177,28 +133,97 @@ fn scalar_format<Tag>(value: ScalarMaybeUndef<Tag>) -> String {
177
133
}
178
134
}
179
135
180
- struct ValidityVisitor < ' rt , ' tcx , Tag > {
136
+ struct ValidityVisitor < ' rt , ' a , ' tcx , Tag > {
181
137
op : OpTy < ' tcx , Tag > ,
182
138
/// The `path` may be pushed to, but the part that is present when a function
183
139
/// starts must not be changed! `visit_fields` and `visit_array` rely on
184
140
/// this stack discipline.
185
141
path : Vec < PathElem > ,
186
142
ref_tracking : Option < & ' rt mut RefTracking < ' tcx , Tag > > ,
187
143
const_mode : bool ,
144
+ tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
188
145
}
189
146
190
- impl < Tag : fmt:: Debug > fmt:: Debug for ValidityVisitor < ' _ , ' _ , Tag > {
147
+ impl < Tag : fmt:: Debug > fmt:: Debug for ValidityVisitor < ' _ , ' _ , ' _ , Tag > {
191
148
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
192
- write ! ( f, "{:?} ({:?})" , * self . op, self . op. layout. ty)
149
+ write ! ( f, "{:?}, {:?}" , * self . op, self . op. layout. ty)
150
+ }
151
+ }
152
+
153
+ impl < ' rt , ' a , ' tcx , Tag > ValidityVisitor < ' rt , ' a , ' tcx , Tag > {
154
+ fn push_aggregate_field_path_elem (
155
+ & mut self ,
156
+ layout : TyLayout < ' tcx > ,
157
+ field : usize ,
158
+ ) {
159
+ let elem = match layout. ty . sty {
160
+ // generators and closures.
161
+ ty:: Closure ( def_id, _) | ty:: Generator ( def_id, _, _) => {
162
+ if let Some ( upvar) = self . tcx . optimized_mir ( def_id) . upvar_decls . get ( field) {
163
+ PathElem :: ClosureVar ( upvar. debug_name )
164
+ } else {
165
+ // Sometimes the index is beyond the number of freevars (seen
166
+ // for a generator).
167
+ PathElem :: ClosureVar ( Symbol :: intern ( & field. to_string ( ) ) )
168
+ }
169
+ }
170
+
171
+ // tuples
172
+ ty:: Tuple ( _) => PathElem :: TupleElem ( field) ,
173
+
174
+ // enums
175
+ ty:: Adt ( def, ..) if def. is_enum ( ) => {
176
+ let variant = match layout. variants {
177
+ layout:: Variants :: Single { index } => & def. variants [ index] ,
178
+ _ => bug ! ( "aggregate_field_path_elem: got enum but not in a specific variant" ) ,
179
+ } ;
180
+ PathElem :: Field ( variant. fields [ field] . ident . name )
181
+ }
182
+
183
+ // other ADTs
184
+ ty:: Adt ( def, _) => PathElem :: Field ( def. non_enum_variant ( ) . fields [ field] . ident . name ) ,
185
+
186
+ // arrays/slices
187
+ ty:: Array ( ..) | ty:: Slice ( ..) => PathElem :: ArrayElem ( field) ,
188
+
189
+ // dyn traits
190
+ ty:: Dynamic ( ..) => PathElem :: DynDowncast ,
191
+
192
+ // nothing else has an aggregate layout
193
+ _ => bug ! ( "aggregate_field_path_elem: got non-aggregate type {:?}" , layout. ty) ,
194
+ } ;
195
+ self . path . push ( elem) ;
193
196
}
194
197
}
195
198
196
199
impl < ' rt , ' a , ' mir , ' tcx , M : Machine < ' a , ' mir , ' tcx > >
197
- ValueVisitor < ' a , ' mir , ' tcx , M > for ValidityVisitor < ' rt , ' tcx , M :: PointerTag >
200
+ ValueVisitor < ' a , ' mir , ' tcx , M > for ValidityVisitor < ' rt , ' a , ' tcx , M :: PointerTag >
198
201
{
202
+ type V = OpTy < ' tcx , M :: PointerTag > ;
203
+
199
204
#[ inline( always) ]
200
- fn layout ( & self ) -> TyLayout < ' tcx > {
201
- self . op . layout
205
+ fn value ( & self ) -> & OpTy < ' tcx , M :: PointerTag > {
206
+ & self . op
207
+ }
208
+
209
+ #[ inline]
210
+ fn with_field (
211
+ & mut self ,
212
+ val : Self :: V ,
213
+ field : usize ,
214
+ f : impl FnOnce ( & mut Self ) -> EvalResult < ' tcx > ,
215
+ ) -> EvalResult < ' tcx > {
216
+ // Remember the old state
217
+ let path_len = self . path . len ( ) ;
218
+ let op = self . op ;
219
+ // Perform operation
220
+ self . push_aggregate_field_path_elem ( op. layout , field) ;
221
+ self . op = val;
222
+ f ( self ) ?;
223
+ // Undo changes
224
+ self . path . truncate ( path_len) ;
225
+ self . op = op;
226
+ Ok ( ( ) )
202
227
}
203
228
204
229
fn downcast_enum ( & mut self , ectx : & EvalContext < ' a , ' mir , ' tcx , M > )
@@ -227,15 +252,6 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
227
252
Ok ( ( ) )
228
253
}
229
254
230
- fn downcast_dyn_trait ( & mut self , ectx : & EvalContext < ' a , ' mir , ' tcx , M > )
231
- -> EvalResult < ' tcx >
232
- {
233
- // FIXME: Should we reflect this in `self.path`?
234
- let dest = self . op . to_mem_place ( ) ; // immediate trait objects are not a thing
235
- self . op = ectx. unpack_dyn_trait ( dest) ?. 1 . into ( ) ;
236
- Ok ( ( ) )
237
- }
238
-
239
255
fn visit_primitive ( & mut self , ectx : & mut EvalContext < ' a , ' mir , ' tcx , M > )
240
256
-> EvalResult < ' tcx >
241
257
{
@@ -365,7 +381,13 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
365
381
let op = place. into ( ) ;
366
382
if ref_tracking. seen . insert ( op) {
367
383
trace ! ( "Recursing below ptr {:#?}" , * op) ;
368
- ref_tracking. todo . push ( ( op, path_clone_and_deref ( & self . path ) ) ) ;
384
+ // We need to clone the path anyway, make sure it gets created
385
+ // with enough space for the additional `Deref`.
386
+ let mut new_path = Vec :: with_capacity ( self . path . len ( ) +1 ) ;
387
+ new_path. clone_from ( & self . path ) ;
388
+ new_path. push ( PathElem :: Deref ) ;
389
+ // Remember to come back to this later.
390
+ ref_tracking. todo . push ( ( op, new_path) ) ;
369
391
}
370
392
}
371
393
}
@@ -378,12 +400,17 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
378
400
// FIXME: Check if the signature matches
379
401
}
380
402
// This should be all the primitive types
381
- ty:: Never => bug ! ( "Uninhabited type should have been caught earlier" ) ,
382
403
_ => bug ! ( "Unexpected primitive type {}" , value. layout. ty)
383
404
}
384
405
Ok ( ( ) )
385
406
}
386
407
408
+ fn visit_uninhabited ( & mut self , _ectx : & mut EvalContext < ' a , ' mir , ' tcx , M > )
409
+ -> EvalResult < ' tcx >
410
+ {
411
+ validation_failure ! ( "a value of an uninhabited type" , self . path)
412
+ }
413
+
387
414
fn visit_scalar ( & mut self , ectx : & mut EvalContext < ' a , ' mir , ' tcx , M > , layout : & layout:: Scalar )
388
415
-> EvalResult < ' tcx >
389
416
{
@@ -468,47 +495,16 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
468
495
}
469
496
}
470
497
471
- fn visit_fields ( & mut self , ectx : & mut EvalContext < ' a , ' mir , ' tcx , M > , num_fields : usize )
472
- -> EvalResult < ' tcx >
473
- {
474
- // Remember some stuff that will change for the recursive calls
475
- let op = self . op ;
476
- let path_len = self . path . len ( ) ;
477
- // Go look at all the fields
478
- for i in 0 ..num_fields {
479
- // Adapt our state
480
- self . op = ectx. operand_field ( op, i as u64 ) ?;
481
- self . path . push ( aggregate_field_path_elem ( op. layout , i, * ectx. tcx ) ) ;
482
- // Recursive visit
483
- ectx. visit_value ( self ) ?;
484
- // Restore original state
485
- self . op = op;
486
- self . path . truncate ( path_len) ;
487
- }
488
- Ok ( ( ) )
489
- }
490
-
491
- fn visit_str ( & mut self , ectx : & mut EvalContext < ' a , ' mir , ' tcx , M > )
492
- -> EvalResult < ' tcx >
493
- {
494
- let mplace = self . op . to_mem_place ( ) ; // strings are never immediate
495
- try_validation ! ( ectx. read_str( mplace) ,
496
- "uninitialized or non-UTF-8 data in str" , self . path) ;
497
- Ok ( ( ) )
498
- }
499
-
500
- fn visit_array ( & mut self , ectx : & mut EvalContext < ' a , ' mir , ' tcx , M > ) -> EvalResult < ' tcx >
498
+ fn handle_array ( & mut self , ectx : & EvalContext < ' a , ' mir , ' tcx , M > )
499
+ -> EvalResult < ' tcx , bool >
501
500
{
502
- let mplace = if self . op . layout . is_zst ( ) {
503
- // it's a ZST, the memory content cannot matter
504
- MPlaceTy :: dangling ( self . op . layout , ectx)
505
- } else {
506
- // non-ZST array/slice/str cannot be immediate
507
- self . op . to_mem_place ( )
508
- } ;
509
- match self . op . layout . ty . sty {
510
- ty:: Str => bug ! ( "Strings should be handled separately" ) ,
511
- // Special handling for arrays/slices of builtin integer types
501
+ Ok ( match self . op . layout . ty . sty {
502
+ ty:: Str => {
503
+ let mplace = self . op . to_mem_place ( ) ; // strings are never immediate
504
+ try_validation ! ( ectx. read_str( mplace) ,
505
+ "uninitialized or non-UTF-8 data in str" , self . path) ;
506
+ true
507
+ }
512
508
ty:: Array ( tys, ..) | ty:: Slice ( tys) if {
513
509
// This optimization applies only for integer and floating point types
514
510
// (i.e., types that can hold arbitrary bytes).
@@ -517,6 +513,13 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
517
513
_ => false ,
518
514
}
519
515
} => {
516
+ let mplace = if self . op . layout . is_zst ( ) {
517
+ // it's a ZST, the memory content cannot matter
518
+ MPlaceTy :: dangling ( self . op . layout , ectx)
519
+ } else {
520
+ // non-ZST array/slice/str cannot be immediate
521
+ self . op . to_mem_place ( )
522
+ } ;
520
523
// This is the length of the array/slice.
521
524
let len = mplace. len ( ectx) ?;
522
525
// This is the element type size.
@@ -539,7 +542,7 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
539
542
/*allow_ptr_and_undef*/ !self . const_mode ,
540
543
) {
541
544
// In the happy case, we needn't check anything else.
542
- Ok ( ( ) ) => { } ,
545
+ Ok ( ( ) ) => true , // handled these arrays
543
546
// Some error happened, try to provide a more detailed description.
544
547
Err ( err) => {
545
548
// For some errors we might be able to provide extra information
@@ -560,26 +563,9 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>
560
563
}
561
564
}
562
565
}
563
- } ,
564
- _ => {
565
- // Remember some stuff that will change for the recursive calls
566
- let op = self . op ;
567
- let path_len = self . path . len ( ) ;
568
- // This handles the unsized case correctly as well, as well as
569
- // SIMD and all sorts of other array-like types.
570
- for ( i, field) in ectx. mplace_array_fields ( mplace) ?. enumerate ( ) {
571
- // Adapt our state
572
- self . op = field?. into ( ) ;
573
- self . path . push ( PathElem :: ArrayElem ( i) ) ;
574
- // Recursive visit
575
- ectx. visit_value ( self ) ?;
576
- // Restore original state
577
- self . op = op;
578
- self . path . truncate ( path_len) ;
579
- }
580
566
}
581
- }
582
- Ok ( ( ) )
567
+ _ => false , // not handled
568
+ } )
583
569
}
584
570
}
585
571
@@ -605,7 +591,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
605
591
op,
606
592
path,
607
593
ref_tracking,
608
- const_mode
594
+ const_mode,
595
+ tcx : * self . tcx ,
609
596
} ;
610
597
611
598
// Run it
0 commit comments