7
7
//! short-circuiting the empty case!
8
8
9
9
use std:: assert_matches:: assert_matches;
10
- use std:: borrow:: Cow ;
10
+ use std:: borrow:: { Borrow , Cow } ;
11
11
use std:: cell:: Cell ;
12
12
use std:: collections:: VecDeque ;
13
13
use std:: { fmt, ptr} ;
@@ -387,12 +387,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
387
387
size : Size ,
388
388
) -> InterpResult < ' tcx , Option < ( AllocId , Size , M :: ProvenanceExtra ) > > {
389
389
let size = i64:: try_from ( size. bytes ( ) ) . unwrap ( ) ; // it would be an error to even ask for more than isize::MAX bytes
390
- self . check_and_deref_ptr (
390
+ Self :: check_and_deref_ptr (
391
+ self ,
391
392
ptr,
392
393
size,
393
394
CheckInAllocMsg :: MemoryAccessTest ,
394
- |alloc_id, offset, prov| {
395
- let ( size, align) = self
395
+ |this , alloc_id, offset, prov| {
396
+ let ( size, align) = this
396
397
. get_live_alloc_size_and_align ( alloc_id, CheckInAllocMsg :: MemoryAccessTest ) ?;
397
398
Ok ( ( size, align, ( alloc_id, offset, prov) ) )
398
399
} ,
@@ -409,8 +410,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
409
410
msg : CheckInAllocMsg ,
410
411
) -> InterpResult < ' tcx > {
411
412
let size = i64:: try_from ( size. bytes ( ) ) . unwrap ( ) ; // it would be an error to even ask for more than isize::MAX bytes
412
- self . check_and_deref_ptr ( ptr, size, msg, |alloc_id, _, _| {
413
- let ( size, align) = self . get_live_alloc_size_and_align ( alloc_id, msg) ?;
413
+ Self :: check_and_deref_ptr ( self , ptr, size, msg, |this , alloc_id, _, _| {
414
+ let ( size, align) = this . get_live_alloc_size_and_align ( alloc_id, msg) ?;
414
415
Ok ( ( size, align, ( ) ) )
415
416
} ) ?;
416
417
Ok ( ( ) )
@@ -425,8 +426,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
425
426
size : i64 ,
426
427
msg : CheckInAllocMsg ,
427
428
) -> InterpResult < ' tcx > {
428
- self . check_and_deref_ptr ( ptr, size, msg, |alloc_id, _, _| {
429
- let ( size, align) = self . get_live_alloc_size_and_align ( alloc_id, msg) ?;
429
+ Self :: check_and_deref_ptr ( self , ptr, size, msg, |this , alloc_id, _, _| {
430
+ let ( size, align) = this . get_live_alloc_size_and_align ( alloc_id, msg) ?;
430
431
Ok ( ( size, align, ( ) ) )
431
432
} ) ?;
432
433
Ok ( ( ) )
@@ -440,12 +441,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
440
441
/// `alloc_size` will only get called for non-zero-sized accesses.
441
442
///
442
443
/// Returns `None` if and only if the size is 0.
443
- fn check_and_deref_ptr < T > (
444
- & self ,
444
+ fn check_and_deref_ptr < T , R : Borrow < Self > > (
445
+ this : R ,
445
446
ptr : Pointer < Option < M :: Provenance > > ,
446
447
size : i64 ,
447
448
msg : CheckInAllocMsg ,
448
449
alloc_size : impl FnOnce (
450
+ R ,
449
451
AllocId ,
450
452
Size ,
451
453
M :: ProvenanceExtra ,
@@ -456,13 +458,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
456
458
return Ok ( None ) ;
457
459
}
458
460
459
- Ok ( match self . ptr_try_get_alloc_id ( ptr, size) {
461
+ Ok ( match this . borrow ( ) . ptr_try_get_alloc_id ( ptr, size) {
460
462
Err ( addr) => {
461
463
// We couldn't get a proper allocation.
462
464
throw_ub ! ( DanglingIntPointer { addr, inbounds_size: size, msg } ) ;
463
465
}
464
466
Ok ( ( alloc_id, offset, prov) ) => {
465
- let ( alloc_size, _alloc_align, ret_val) = alloc_size ( alloc_id, offset, prov) ?;
467
+ let tcx = this. borrow ( ) . tcx ;
468
+ let ( alloc_size, _alloc_align, ret_val) = alloc_size ( this, alloc_id, offset, prov) ?;
466
469
let offset = offset. bytes ( ) ;
467
470
// Compute absolute begin and end of the range.
468
471
let ( begin, end) = if size >= 0 {
@@ -476,7 +479,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
476
479
throw_ub ! ( PointerOutOfBounds {
477
480
alloc_id,
478
481
alloc_size,
479
- ptr_offset: self . sign_extend_to_target_isize( offset) ,
482
+ ptr_offset: tcx . sign_extend_to_target_isize( offset) ,
480
483
inbounds_size: size,
481
484
msg,
482
485
} )
@@ -670,12 +673,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
670
673
) -> InterpResult < ' tcx , Option < AllocRef < ' a , ' tcx , M :: Provenance , M :: AllocExtra , M :: Bytes > > >
671
674
{
672
675
let size_i64 = i64:: try_from ( size. bytes ( ) ) . unwrap ( ) ; // it would be an error to even ask for more than isize::MAX bytes
673
- let ptr_and_alloc = self . check_and_deref_ptr (
676
+ let ptr_and_alloc = Self :: check_and_deref_ptr (
677
+ self ,
674
678
ptr,
675
679
size_i64,
676
680
CheckInAllocMsg :: MemoryAccessTest ,
677
- |alloc_id, offset, prov| {
678
- let alloc = self . get_alloc_raw ( alloc_id) ?;
681
+ |this , alloc_id, offset, prov| {
682
+ let alloc = this . get_alloc_raw ( alloc_id) ?;
679
683
Ok ( ( alloc. size ( ) , alloc. align , ( alloc_id, offset, prov, alloc) ) )
680
684
} ,
681
685
) ?;
@@ -727,7 +731,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
727
731
// We have "NLL problem case #3" here, which cannot be worked around without loss of
728
732
// efficiency even for the common case where the key is in the map.
729
733
// <https://rust-lang.github.io/rfcs/2094-nll.html#problem-case-3-conditional-control-flow-across-functions>
730
- // (Cannot use `get_mut_or` since `get_global_alloc` needs `&self`.)
734
+ // (Cannot use `get_mut_or` since `get_global_alloc` needs `&self`, and that boils down to
735
+ // Miri's `adjust_alloc_root_pointer` needing to look up the size of the allocation.
736
+ // It could be avoided with a totally separate codepath in Miri for handling the absolute address
737
+ // of global allocations, but that's not worth it.)
731
738
if self . memory . alloc_map . get_mut ( id) . is_none ( ) {
732
739
// Slow path.
733
740
// Allocation not found locally, go look global.
@@ -763,12 +770,21 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
763
770
size : Size ,
764
771
) -> InterpResult < ' tcx , Option < AllocRefMut < ' a , ' tcx , M :: Provenance , M :: AllocExtra , M :: Bytes > > >
765
772
{
766
- let parts = self . get_ptr_access ( ptr, size) ?;
767
- if let Some ( ( alloc_id, offset, prov) ) = parts {
768
- let tcx = self . tcx ;
769
- // FIXME: can we somehow avoid looking up the allocation twice here?
770
- // We cannot call `get_raw_mut` inside `check_and_deref_ptr` as that would duplicate `&mut self`.
771
- let ( alloc, machine) = self . get_alloc_raw_mut ( alloc_id) ?;
773
+ let tcx = self . tcx ;
774
+
775
+ let size_i64 = i64:: try_from ( size. bytes ( ) ) . unwrap ( ) ; // it would be an error to even ask for more than isize::MAX bytes
776
+ let ptr_and_alloc = Self :: check_and_deref_ptr (
777
+ self ,
778
+ ptr,
779
+ size_i64,
780
+ CheckInAllocMsg :: MemoryAccessTest ,
781
+ |this, alloc_id, offset, prov| {
782
+ let ( alloc, machine) = this. get_alloc_raw_mut ( alloc_id) ?;
783
+ Ok ( ( alloc. size ( ) , alloc. align , ( alloc_id, offset, prov, alloc, machine) ) )
784
+ } ,
785
+ ) ?;
786
+
787
+ if let Some ( ( alloc_id, offset, prov, alloc, machine) ) = ptr_and_alloc {
772
788
let range = alloc_range ( offset, size) ;
773
789
M :: before_memory_write ( tcx, machine, & mut alloc. extra , ( alloc_id, prov) , range) ?;
774
790
Ok ( Some ( AllocRefMut { alloc, range, tcx : * tcx, alloc_id } ) )
0 commit comments