77//! short-circuiting the empty case!
88
99use std:: assert_matches:: assert_matches;
10- use std:: borrow:: Cow ;
10+ use std:: borrow:: { Borrow , Cow } ;
1111use std:: collections:: VecDeque ;
1212use std:: { fmt, mem, ptr} ;
1313
@@ -386,12 +386,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
386386 size : Size ,
387387 ) -> InterpResult < ' tcx , Option < ( AllocId , Size , M :: ProvenanceExtra ) > > {
388388 let size = i64:: try_from ( size. bytes ( ) ) . unwrap ( ) ; // it would be an error to even ask for more than isize::MAX bytes
389- self . check_and_deref_ptr (
389+ Self :: check_and_deref_ptr (
390+ self ,
390391 ptr,
391392 size,
392393 CheckInAllocMsg :: MemoryAccessTest ,
393- |alloc_id, offset, prov| {
394- let ( size, align) = self
394+ |this , alloc_id, offset, prov| {
395+ let ( size, align) = this
395396 . get_live_alloc_size_and_align ( alloc_id, CheckInAllocMsg :: MemoryAccessTest ) ?;
396397 Ok ( ( size, align, ( alloc_id, offset, prov) ) )
397398 } ,
@@ -408,8 +409,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
408409 msg : CheckInAllocMsg ,
409410 ) -> InterpResult < ' tcx > {
410411 let size = i64:: try_from ( size. bytes ( ) ) . unwrap ( ) ; // it would be an error to even ask for more than isize::MAX bytes
411- self . check_and_deref_ptr ( ptr, size, msg, |alloc_id, _, _| {
412- let ( size, align) = self . get_live_alloc_size_and_align ( alloc_id, msg) ?;
412+ Self :: check_and_deref_ptr ( self , ptr, size, msg, |this , alloc_id, _, _| {
413+ let ( size, align) = this . get_live_alloc_size_and_align ( alloc_id, msg) ?;
413414 Ok ( ( size, align, ( ) ) )
414415 } ) ?;
415416 Ok ( ( ) )
@@ -424,8 +425,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
424425 size : i64 ,
425426 msg : CheckInAllocMsg ,
426427 ) -> InterpResult < ' tcx > {
427- self . check_and_deref_ptr ( ptr, size, msg, |alloc_id, _, _| {
428- let ( size, align) = self . get_live_alloc_size_and_align ( alloc_id, msg) ?;
428+ Self :: check_and_deref_ptr ( self , ptr, size, msg, |this , alloc_id, _, _| {
429+ let ( size, align) = this . get_live_alloc_size_and_align ( alloc_id, msg) ?;
429430 Ok ( ( size, align, ( ) ) )
430431 } ) ?;
431432 Ok ( ( ) )
@@ -439,12 +440,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
439440 /// `alloc_size` will only get called for non-zero-sized accesses.
440441 ///
441442 /// Returns `None` if and only if the size is 0.
442- fn check_and_deref_ptr < T > (
443- & self ,
443+ fn check_and_deref_ptr < T , R : Borrow < Self > > (
444+ this : R ,
444445 ptr : Pointer < Option < M :: Provenance > > ,
445446 size : i64 ,
446447 msg : CheckInAllocMsg ,
447448 alloc_size : impl FnOnce (
449+ R ,
448450 AllocId ,
449451 Size ,
450452 M :: ProvenanceExtra ,
@@ -455,13 +457,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
455457 return Ok ( None ) ;
456458 }
457459
458- Ok ( match self . ptr_try_get_alloc_id ( ptr, size) {
460+ Ok ( match this . borrow ( ) . ptr_try_get_alloc_id ( ptr, size) {
459461 Err ( addr) => {
460462 // We couldn't get a proper allocation.
461463 throw_ub ! ( DanglingIntPointer { addr, inbounds_size: size, msg } ) ;
462464 }
463465 Ok ( ( alloc_id, offset, prov) ) => {
464- let ( alloc_size, _alloc_align, ret_val) = alloc_size ( alloc_id, offset, prov) ?;
466+ let tcx = this. borrow ( ) . tcx ;
467+ let ( alloc_size, _alloc_align, ret_val) = alloc_size ( this, alloc_id, offset, prov) ?;
465468 let offset = offset. bytes ( ) ;
466469 // Compute absolute begin and end of the range.
467470 let ( begin, end) = if size >= 0 {
@@ -475,7 +478,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
475478 throw_ub ! ( PointerOutOfBounds {
476479 alloc_id,
477480 alloc_size,
478- ptr_offset: self . sign_extend_to_target_isize( offset) ,
481+ ptr_offset: tcx . sign_extend_to_target_isize( offset) ,
479482 inbounds_size: size,
480483 msg,
481484 } )
@@ -669,12 +672,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
669672 ) -> InterpResult < ' tcx , Option < AllocRef < ' a , ' tcx , M :: Provenance , M :: AllocExtra , M :: Bytes > > >
670673 {
671674 let size_i64 = i64:: try_from ( size. bytes ( ) ) . unwrap ( ) ; // it would be an error to even ask for more than isize::MAX bytes
672- let ptr_and_alloc = self . check_and_deref_ptr (
675+ let ptr_and_alloc = Self :: check_and_deref_ptr (
676+ self ,
673677 ptr,
674678 size_i64,
675679 CheckInAllocMsg :: MemoryAccessTest ,
676- |alloc_id, offset, prov| {
677- let alloc = self . get_alloc_raw ( alloc_id) ?;
680+ |this , alloc_id, offset, prov| {
681+ let alloc = this . get_alloc_raw ( alloc_id) ?;
678682 Ok ( ( alloc. size ( ) , alloc. align , ( alloc_id, offset, prov, alloc) ) )
679683 } ,
680684 ) ?;
@@ -726,7 +730,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
726730 // We have "NLL problem case #3" here, which cannot be worked around without loss of
727731 // efficiency even for the common case where the key is in the map.
728732 // <https://rust-lang.github.io/rfcs/2094-nll.html#problem-case-3-conditional-control-flow-across-functions>
729- // (Cannot use `get_mut_or` since `get_global_alloc` needs `&self`.)
733+ // (Cannot use `get_mut_or` since `get_global_alloc` needs `&self`, and that boils down to
734+ // Miri's `adjust_alloc_root_pointer` needing to look up the size of the allocation.
735+ // It could be avoided with a totally separate codepath in Miri for handling the absolute address
736+ // of global allocations, but that's not worth it.)
730737 if self . memory . alloc_map . get_mut ( id) . is_none ( ) {
731738 // Slow path.
732739 // Allocation not found locally, go look global.
@@ -762,13 +769,22 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
762769 size : Size ,
763770 ) -> InterpResult < ' tcx , Option < AllocRefMut < ' a , ' tcx , M :: Provenance , M :: AllocExtra , M :: Bytes > > >
764771 {
765- let parts = self . get_ptr_access ( ptr, size) ?;
766- if let Some ( ( alloc_id, offset, prov) ) = parts {
767- let tcx = self . tcx ;
768- let validation_in_progress = self . memory . validation_in_progress ;
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) ?;
772+ let tcx = self . tcx ;
773+ let validation_in_progress = self . memory . validation_in_progress ;
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 {
772788 let range = alloc_range ( offset, size) ;
773789 if !validation_in_progress {
774790 M :: before_memory_write ( tcx, machine, & mut alloc. extra , ( alloc_id, prov) , range) ?;
0 commit comments