19
19
use std:: collections:: VecDeque ;
20
20
use std:: ptr;
21
21
22
- use rustc:: ty:: { self , Instance , query:: TyCtxtAt } ;
22
+ use rustc:: ty:: { self , Instance , ParamEnv , query:: TyCtxtAt } ;
23
23
use rustc:: ty:: layout:: { self , Align , TargetDataLayout , Size , HasDataLayout } ;
24
24
use rustc:: mir:: interpret:: { Pointer , AllocId , Allocation , ConstValue , GlobalId ,
25
25
EvalResult , Scalar , EvalErrorKind , AllocType , PointerArithmetic ,
@@ -235,7 +235,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
235
235
// Check non-NULL/Undef, extract offset
236
236
let ( offset, alloc_align) = match ptr {
237
237
Scalar :: Ptr ( ptr) => {
238
- let ( size, align) = self . get_size_and_align ( ptr. alloc_id ) ? ;
238
+ let ( size, align) = self . get_size_and_align ( ptr. alloc_id ) ;
239
239
// check this is not NULL -- which we can ensure only if this is in-bounds
240
240
// of some (potentially dead) allocation.
241
241
if ptr. offset > size {
@@ -284,7 +284,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
284
284
/// If you want to check bounds before doing a memory access, be sure to
285
285
/// check the pointer one past the end of your access, then everything will
286
286
/// work out exactly.
287
- pub fn check_bounds ( & self , ptr : Pointer , access : bool ) -> EvalResult < ' tcx > {
287
+ pub fn check_bounds_ptr ( & self , ptr : Pointer , access : bool ) -> EvalResult < ' tcx > {
288
288
let alloc = self . get ( ptr. alloc_id ) ?;
289
289
let allocation_size = alloc. bytes . len ( ) as u64 ;
290
290
if ptr. offset . bytes ( ) > allocation_size {
@@ -296,6 +296,13 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
296
296
}
297
297
Ok ( ( ) )
298
298
}
299
+
300
+ /// Check if the memory range beginning at `ptr` and of size `Size` is "in-bounds".
301
+ #[ inline( always) ]
302
+ pub fn check_bounds ( & self , ptr : Pointer , size : Size , access : bool ) -> EvalResult < ' tcx > {
303
+ // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow)
304
+ self . check_bounds_ptr ( ptr. offset ( size, & * self ) ?, access)
305
+ }
299
306
}
300
307
301
308
/// Allocation accessors
@@ -352,19 +359,28 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
352
359
}
353
360
}
354
361
355
- pub fn get_size_and_align ( & self , id : AllocId ) -> EvalResult < ' tcx , ( Size , Align ) > {
356
- Ok ( match self . get ( id) {
357
- Ok ( alloc) => ( Size :: from_bytes ( alloc. bytes . len ( ) as u64 ) , alloc. align ) ,
358
- Err ( err) => match err. kind {
359
- EvalErrorKind :: DanglingPointerDeref =>
360
- // This should be in the dead allocation map
361
- * self . dead_alloc_map . get ( & id) . expect (
362
- "allocation missing in dead_alloc_map"
363
- ) ,
364
- // E.g. a function ptr allocation
365
- _ => return Err ( err)
362
+ pub fn get_size_and_align ( & self , id : AllocId ) -> ( Size , Align ) {
363
+ if let Ok ( alloc) = self . get ( id) {
364
+ return ( Size :: from_bytes ( alloc. bytes . len ( ) as u64 ) , alloc. align ) ;
365
+ }
366
+ // Could also be a fn ptr or extern static
367
+ match self . tcx . alloc_map . lock ( ) . get ( id) {
368
+ Some ( AllocType :: Function ( ..) ) => ( Size :: ZERO , Align :: from_bytes ( 1 , 1 ) . unwrap ( ) ) ,
369
+ Some ( AllocType :: Static ( did) ) => {
370
+ // The only way `get` couldnÄt have worked here is if this is an extern static
371
+ assert ! ( self . tcx. is_foreign_item( did) ) ;
372
+ // Use size and align of the type
373
+ let ty = self . tcx . type_of ( did) ;
374
+ let layout = self . tcx . layout_of ( ParamEnv :: empty ( ) . and ( ty) ) . unwrap ( ) ;
375
+ ( layout. size , layout. align )
366
376
}
367
- } )
377
+ _ => {
378
+ // Must be a deallocated pointer
379
+ * self . dead_alloc_map . get ( & id) . expect (
380
+ "allocation missing in dead_alloc_map"
381
+ )
382
+ }
383
+ }
368
384
}
369
385
370
386
pub fn get_mut (
@@ -524,8 +540,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
524
540
) -> EvalResult < ' tcx , & [ u8 ] > {
525
541
assert_ne ! ( size. bytes( ) , 0 , "0-sized accesses should never even get a `Pointer`" ) ;
526
542
self . check_align ( ptr. into ( ) , align) ?;
527
- // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow)
528
- self . check_bounds ( ptr. offset ( size, & * self ) ?, true ) ?;
543
+ self . check_bounds ( ptr, size, true ) ?;
529
544
530
545
if check_defined_and_ptr {
531
546
self . check_defined ( ptr, size) ?;
@@ -569,8 +584,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
569
584
) -> EvalResult < ' tcx , & mut [ u8 ] > {
570
585
assert_ne ! ( size. bytes( ) , 0 , "0-sized accesses should never even get a `Pointer`" ) ;
571
586
self . check_align ( ptr. into ( ) , align) ?;
572
- // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow)
573
- self . check_bounds ( ptr. offset ( size, & self ) ?, true ) ?;
587
+ self . check_bounds ( ptr, size, true ) ?;
574
588
575
589
self . mark_definedness ( ptr, size, true ) ?;
576
590
self . clear_relocations ( ptr, size) ?;
0 commit comments