@@ -262,7 +262,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
262
262
Scalar :: Ptr ( ptr) => {
263
263
// check this is not NULL -- which we can ensure only if this is in-bounds
264
264
// of some (potentially dead) allocation.
265
- let align = self . check_bounds_ptr_maybe_dead ( ptr) ?;
265
+ let align = self . check_bounds_ptr ( ptr, InboundsCheck :: MaybeDead ) ?;
266
266
( ptr. offset . bytes ( ) , align)
267
267
}
268
268
Scalar :: Bits { bits, size } => {
@@ -297,17 +297,15 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
297
297
/// Check if the pointer is "in-bounds". Notice that a pointer pointing at the end
298
298
/// of an allocation (i.e., at the first *inaccessible* location) *is* considered
299
299
/// in-bounds! This follows C's/LLVM's rules.
300
- /// This function also works for deallocated allocations.
301
- /// Use `.get(ptr.alloc_id)?.check_bounds_ptr(ptr)` if you want to force the allocation
302
- /// to still be live.
303
300
/// If you want to check bounds before doing a memory access, better first obtain
304
301
/// an `Allocation` and call `check_bounds`.
305
- pub fn check_bounds_ptr_maybe_dead (
302
+ pub fn check_bounds_ptr (
306
303
& self ,
307
304
ptr : Pointer < M :: PointerTag > ,
305
+ liveness : InboundsCheck ,
308
306
) -> EvalResult < ' tcx , Align > {
309
- let ( allocation_size, align) = self . get_size_and_align ( ptr. alloc_id ) ;
310
- ptr. check_in_alloc ( allocation_size, InboundsCheck :: MaybeDead ) ?;
307
+ let ( allocation_size, align) = self . get_size_and_align ( ptr. alloc_id , liveness ) ? ;
308
+ ptr. check_in_alloc ( allocation_size, liveness ) ?;
311
309
Ok ( align)
312
310
}
313
311
}
@@ -429,27 +427,37 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
429
427
}
430
428
}
431
429
432
- pub fn get_size_and_align ( & self , id : AllocId ) -> ( Size , Align ) {
430
+ /// Obtain the size and alignment of an allocation, even if that allocation has been deallocated
431
+ ///
432
+ /// If `liveness` is `InboundsCheck::Dead`, this function always returns `Ok`
433
+ pub fn get_size_and_align (
434
+ & self ,
435
+ id : AllocId ,
436
+ liveness : InboundsCheck ,
437
+ ) -> EvalResult < ' static , ( Size , Align ) > {
433
438
if let Ok ( alloc) = self . get ( id) {
434
- return ( Size :: from_bytes ( alloc. bytes . len ( ) as u64 ) , alloc. align ) ;
439
+ return Ok ( ( Size :: from_bytes ( alloc. bytes . len ( ) as u64 ) , alloc. align ) ) ;
435
440
}
436
441
// Could also be a fn ptr or extern static
437
442
match self . tcx . alloc_map . lock ( ) . get ( id) {
438
- Some ( AllocKind :: Function ( ..) ) => ( Size :: ZERO , Align :: from_bytes ( 1 ) . unwrap ( ) ) ,
443
+ Some ( AllocKind :: Function ( ..) ) => Ok ( ( Size :: ZERO , Align :: from_bytes ( 1 ) . unwrap ( ) ) ) ,
439
444
Some ( AllocKind :: Static ( did) ) => {
440
445
// The only way `get` couldn't have worked here is if this is an extern static
441
446
assert ! ( self . tcx. is_foreign_item( did) ) ;
442
447
// Use size and align of the type
443
448
let ty = self . tcx . type_of ( did) ;
444
449
let layout = self . tcx . layout_of ( ParamEnv :: empty ( ) . and ( ty) ) . unwrap ( ) ;
445
- ( layout. size , layout. align . abi )
446
- }
447
- _ => {
448
- // Must be a deallocated pointer
449
- * self . dead_alloc_map . get ( & id) . expect (
450
- "allocation missing in dead_alloc_map"
451
- )
450
+ Ok ( ( layout. size , layout. align . abi ) )
452
451
}
452
+ _ => match liveness {
453
+ InboundsCheck :: MaybeDead => {
454
+ // Must be a deallocated pointer
455
+ Ok ( * self . dead_alloc_map . get ( & id) . expect (
456
+ "allocation missing in dead_alloc_map"
457
+ ) )
458
+ } ,
459
+ InboundsCheck :: Live => err ! ( DanglingPointerDeref ) ,
460
+ } ,
453
461
}
454
462
}
455
463
0 commit comments