@@ -12,7 +12,7 @@ use std::fmt::Write;
12
12
use std:: hash:: Hash ;
13
13
14
14
use syntax_pos:: symbol:: Symbol ;
15
- use rustc:: ty:: layout:: { self , Size , Align , TyLayout } ;
15
+ use rustc:: ty:: layout:: { self , Size , Align , TyLayout , LayoutOf } ;
16
16
use rustc:: ty;
17
17
use rustc_data_structures:: fx:: FxHashSet ;
18
18
use rustc:: mir:: interpret:: {
@@ -176,19 +176,27 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
176
176
// undef. We should fix that, but let's start low.
177
177
}
178
178
}
179
- _ if ty. is_box ( ) || ty. is_region_ptr ( ) || ty. is_unsafe_ptr ( ) => {
180
- // Handle fat pointers. We also check fat raw pointers,
181
- // their metadata must be valid!
182
- // This also checks that the ptr itself is initialized, which
183
- // seems reasonable even for raw pointers.
184
- let place = try_validation ! ( self . ref_to_mplace( value) ,
185
- "undefined data in pointer" , path) ;
179
+ ty:: RawPtr ( ..) => {
180
+ // No undef allowed here. Eventually this should be consistent with
181
+ // the integer types.
182
+ let _ptr = try_validation ! ( value. to_scalar_ptr( ) ,
183
+ "undefined address in pointer" , path) ;
184
+ let _meta = try_validation ! ( value. to_meta( ) ,
185
+ "uninitialized data in fat pointer metadata" , path) ;
186
+ }
187
+ _ if ty. is_box ( ) || ty. is_region_ptr ( ) => {
188
+ // Handle fat pointers.
186
189
// Check metadata early, for better diagnostics
187
- if place. layout . is_unsized ( ) {
188
- let tail = self . tcx . struct_tail ( place. layout . ty ) ;
190
+ let ptr = try_validation ! ( value. to_scalar_ptr( ) ,
191
+ "undefined address in pointer" , path) ;
192
+ let meta = try_validation ! ( value. to_meta( ) ,
193
+ "uninitialized data in fat pointer metadata" , path) ;
194
+ let layout = self . layout_of ( value. layout . ty . builtin_deref ( true ) . unwrap ( ) . ty ) ?;
195
+ if layout. is_unsized ( ) {
196
+ let tail = self . tcx . struct_tail ( layout. ty ) ;
189
197
match tail. sty {
190
198
ty:: Dynamic ( ..) => {
191
- let vtable = try_validation ! ( place . meta. unwrap( ) . to_ptr( ) ,
199
+ let vtable = try_validation ! ( meta. unwrap( ) . to_ptr( ) ,
192
200
"non-pointer vtable in fat pointer" , path) ;
193
201
try_validation ! ( self . read_drop_type_from_vtable( vtable) ,
194
202
"invalid drop fn in vtable" , path) ;
@@ -197,7 +205,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
197
205
// FIXME: More checks for the vtable.
198
206
}
199
207
ty:: Slice ( ..) | ty:: Str => {
200
- try_validation ! ( place . meta. unwrap( ) . to_usize( self ) ,
208
+ try_validation ! ( meta. unwrap( ) . to_usize( self ) ,
201
209
"non-integer slice length in fat pointer" , path) ;
202
210
}
203
211
ty:: Foreign ( ..) => {
@@ -207,59 +215,65 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
207
215
bug ! ( "Unexpected unsized type tail: {:?}" , tail) ,
208
216
}
209
217
}
210
- // for safe ptrs, also check the ptr values itself
211
- if !ty . is_unsafe_ptr ( ) {
212
- // Make sure this is non-NULL and aligned
213
- let ( size, align ) = self . size_and_align_of ( place . meta , place . layout ) ?
214
- // for the purpose of validity, consider foreign types to have
215
- // alignment and size determined by the layout (size will be 0,
216
- // alignment should take attributes into account).
217
- . unwrap_or_else ( || place . layout . size_and_align ( ) ) ;
218
- match self . memory . check_align ( place . ptr , align ) {
219
- Ok ( _ ) => { } ,
220
- Err ( err ) => match err. kind {
218
+ // Make sure this is non-NULL and aligned
219
+ let ( size , align ) = self . size_and_align_of ( meta , layout ) ?
220
+ // for the purpose of validity, consider foreign types to have
221
+ // alignment and size determined by the layout (size will be 0,
222
+ // alignment should take attributes into account).
223
+ . unwrap_or_else ( || layout. size_and_align ( ) ) ;
224
+ match self . memory . check_align ( ptr , align ) {
225
+ Ok ( _ ) => { } ,
226
+ Err ( err ) => {
227
+ error ! ( "{:?} is not aligned to {:?}" , ptr , align ) ;
228
+ match err. kind {
221
229
EvalErrorKind :: InvalidNullPointerUsage =>
222
230
return validation_failure ! ( "NULL reference" , path) ,
223
231
EvalErrorKind :: AlignmentCheckFailed { .. } =>
224
232
return validation_failure ! ( "unaligned reference" , path) ,
225
233
_ =>
226
234
return validation_failure ! (
227
235
"dangling (out-of-bounds) reference (might be NULL at \
228
- run-time)",
236
+ run-time)",
229
237
path
230
238
) ,
231
239
}
232
240
}
233
- // non-ZST also have to be dereferenceable
241
+ }
242
+ // Turn ptr into place.
243
+ // `ref_to_mplace` also calls the machine hook for (re)activating the tag,
244
+ // which in turn will (in full miri) check if the pointer is dereferencable.
245
+ let place = self . ref_to_mplace ( value) ?;
246
+ // Recursive checking
247
+ if let Some ( ref_tracking) = ref_tracking {
248
+ assert ! ( const_mode, "We should only do recursie checking in const mode" ) ;
234
249
if size != Size :: ZERO {
250
+ // Non-ZST also have to be dereferencable
235
251
let ptr = try_validation ! ( place. ptr. to_ptr( ) ,
236
252
"integer pointer in non-ZST reference" , path) ;
237
- if const_mode {
238
- // Skip validation entirely for some external statics
239
- let alloc_kind = self . tcx . alloc_map . lock ( ) . get ( ptr. alloc_id ) ;
240
- if let Some ( AllocType :: Static ( did) ) = alloc_kind {
241
- // `extern static` cannot be validated as they have no body.
242
- // FIXME: Statics from other crates are also skipped.
243
- // They might be checked at a different type, but for now we
244
- // want to avoid recursing too deeply. This is not sound!
245
- if !did. is_local ( ) || self . tcx . is_foreign_item ( did) {
246
- return Ok ( ( ) ) ;
247
- }
253
+ // Skip validation entirely for some external statics
254
+ let alloc_kind = self . tcx . alloc_map . lock ( ) . get ( ptr. alloc_id ) ;
255
+ if let Some ( AllocType :: Static ( did) ) = alloc_kind {
256
+ // `extern static` cannot be validated as they have no body.
257
+ // FIXME: Statics from other crates are also skipped.
258
+ // They might be checked at a different type, but for now we
259
+ // want to avoid recursing too deeply. This is not sound!
260
+ if !did. is_local ( ) || self . tcx . is_foreign_item ( did) {
261
+ return Ok ( ( ) ) ;
248
262
}
249
263
}
264
+ // Maintain the invariant that the place we are checking is
265
+ // already verified to be in-bounds.
250
266
try_validation ! ( self . memory. check_bounds( ptr, size, false ) ,
251
267
"dangling (not entirely in bounds) reference" , path) ;
252
268
}
253
- if let Some ( ref_tracking) = ref_tracking {
254
- // Check if we have encountered this pointer+layout combination
255
- // before. Proceed recursively even for integer pointers, no
256
- // reason to skip them! They are (recursively) valid for some ZST,
257
- // but not for others (e.g. `!` is a ZST).
258
- let op = place. into ( ) ;
259
- if ref_tracking. seen . insert ( op) {
260
- trace ! ( "Recursing below ptr {:#?}" , * op) ;
261
- ref_tracking. todo . push ( ( op, path_clone_and_deref ( path) ) ) ;
262
- }
269
+ // Check if we have encountered this pointer+layout combination
270
+ // before. Proceed recursively even for integer pointers, no
271
+ // reason to skip them! They are (recursively) valid for some ZST,
272
+ // but not for others (e.g. `!` is a ZST).
273
+ let op = place. into ( ) ;
274
+ if ref_tracking. seen . insert ( op) {
275
+ trace ! ( "Recursing below ptr {:#?}" , * op) ;
276
+ ref_tracking. todo . push ( ( op, path_clone_and_deref ( path) ) ) ;
263
277
}
264
278
}
265
279
}
0 commit comments