@@ -12,7 +12,7 @@ use std::fmt::Write;
1212use std:: hash:: Hash ;
1313
1414use syntax_pos:: symbol:: Symbol ;
15- use rustc:: ty:: layout:: { self , Size , Align , TyLayout } ;
15+ use rustc:: ty:: layout:: { self , Size , Align , TyLayout , LayoutOf } ;
1616use rustc:: ty;
1717use rustc_data_structures:: fx:: FxHashSet ;
1818use rustc:: mir:: interpret:: {
@@ -176,19 +176,27 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
176176 // undef. We should fix that, but let's start low.
177177 }
178178 }
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.
186189 // 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 ) ;
189197 match tail. sty {
190198 ty:: Dynamic ( ..) => {
191- let vtable = try_validation ! ( place . meta. unwrap( ) . to_ptr( ) ,
199+ let vtable = try_validation ! ( meta. unwrap( ) . to_ptr( ) ,
192200 "non-pointer vtable in fat pointer" , path) ;
193201 try_validation ! ( self . read_drop_type_from_vtable( vtable) ,
194202 "invalid drop fn in vtable" , path) ;
@@ -197,7 +205,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
197205 // FIXME: More checks for the vtable.
198206 }
199207 ty:: Slice ( ..) | ty:: Str => {
200- try_validation ! ( place . meta. unwrap( ) . to_usize( self ) ,
208+ try_validation ! ( meta. unwrap( ) . to_usize( self ) ,
201209 "non-integer slice length in fat pointer" , path) ;
202210 }
203211 ty:: Foreign ( ..) => {
@@ -207,59 +215,65 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
207215 bug ! ( "Unexpected unsized type tail: {:?}" , tail) ,
208216 }
209217 }
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 {
221229 EvalErrorKind :: InvalidNullPointerUsage =>
222230 return validation_failure ! ( "NULL reference" , path) ,
223231 EvalErrorKind :: AlignmentCheckFailed { .. } =>
224232 return validation_failure ! ( "unaligned reference" , path) ,
225233 _ =>
226234 return validation_failure ! (
227235 "dangling (out-of-bounds) reference (might be NULL at \
228- run-time)",
236+ run-time)",
229237 path
230238 ) ,
231239 }
232240 }
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" ) ;
234249 if size != Size :: ZERO {
250+ // Non-ZST also have to be dereferencable
235251 let ptr = try_validation ! ( place. ptr. to_ptr( ) ,
236252 "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 ( ( ) ) ;
248262 }
249263 }
264+ // Maintain the invariant that the place we are checking is
265+ // already verified to be in-bounds.
250266 try_validation ! ( self . memory. check_bounds( ptr, size, false ) ,
251267 "dangling (not entirely in bounds) reference" , path) ;
252268 }
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) ) ) ;
263277 }
264278 }
265279 }
0 commit comments