@@ -303,6 +303,9 @@ impl<'tcx> Stacks {
303303 trace ! ( "{} access of tag {:?}: {:?}, size {}" ,
304304 if is_write { "read" } else { "write" } ,
305305 ptr. tag, ptr, size. bytes( ) ) ;
306+ // Even reads can have a side-effect, by invalidating other references.
307+ // This is fundamentally necessary since `&mut` asserts that there
308+ // are no accesses through other references, not even reads.
306309 let mut stacks = self . stacks . borrow_mut ( ) ;
307310 for stack in stacks. iter_mut ( ptr. offset , size) {
308311 stack. access ( ptr. tag , is_write) ?;
@@ -311,6 +314,7 @@ impl<'tcx> Stacks {
311314 }
312315
313316 /// Reborrow the given pointer to the new tag for the given kind of reference.
317+ /// This works on `&self` because we might encounter references to constant memory.
314318 fn reborrow (
315319 & self ,
316320 ptr : Pointer < Borrow > ,
@@ -414,8 +418,16 @@ pub trait EvalContextExt<'tcx> {
414418 kind : MemoryKind < MiriMemoryKind > ,
415419 ) -> Borrow ;
416420
417- /// Retag an indidual pointer , returning the retagged version .
421+ /// Reborrow the given place , returning the newly tagged ptr to it .
418422 fn reborrow (
423+ & mut self ,
424+ place : MPlaceTy < ' tcx , Borrow > ,
425+ size : Size ,
426+ new_bor : Borrow
427+ ) -> EvalResult < ' tcx , Pointer < Borrow > > ;
428+
429+ /// Retag an indidual pointer, returning the retagged version.
430+ fn retag_reference (
419431 & mut self ,
420432 ptr : ImmTy < ' tcx , Borrow > ,
421433 mutbl : Mutability ,
@@ -536,22 +548,46 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> {
536548 }
537549
538550 /// The given place may henceforth be accessed through raw pointers.
551+ #[ inline( always) ]
539552 fn escape_to_raw (
540553 & mut self ,
541554 place : MPlaceTy < ' tcx , Borrow > ,
542555 size : Size ,
543556 ) -> EvalResult < ' tcx > {
544- trace ! ( "escape_to_raw: {:?} is now accessible by raw pointers" , * place) ;
545- // Get the allocation
557+ self . reborrow ( place, size, Borrow :: default ( ) ) ?;
558+ Ok ( ( ) )
559+ }
560+
561+ fn reborrow (
562+ & mut self ,
563+ place : MPlaceTy < ' tcx , Borrow > ,
564+ size : Size ,
565+ new_bor : Borrow
566+ ) -> EvalResult < ' tcx , Pointer < Borrow > > {
546567 let ptr = place. ptr . to_ptr ( ) ?;
547- self . memory ( ) . check_bounds ( ptr, size, false ) ?; // `ptr_dereference` wouldn't do any checks if this is a raw ptr
568+ let new_ptr = Pointer :: new_with_tag ( ptr. alloc_id , ptr. offset , new_bor) ;
569+ trace ! ( "reborrow: Creating new reference for {:?} (pointee {}): {:?}" ,
570+ ptr, place. layout. ty, new_bor) ;
571+
572+ // Get the allocation. It might not be mutable, so we cannot use `get_mut`.
573+ self . memory ( ) . check_bounds ( ptr, size, false ) ?;
548574 let alloc = self . memory ( ) . get ( ptr. alloc_id ) . expect ( "We checked that the ptr is fine!" ) ;
549- // Re-borrow to raw. This is a NOP for shared borrows, but we do not know the borrow
550- // type here and that's also okay. Freezing does not matter here.
551- alloc. extra . reborrow ( ptr, size, Borrow :: default ( ) , RefKind :: Raw )
575+ // Update the stacks.
576+ if let Borrow :: Shr ( Some ( _) ) = new_bor {
577+ // Reference that cares about freezing. We need a frozen-sensitive reborrow.
578+ self . visit_freeze_sensitive ( place, size, |cur_ptr, size, frozen| {
579+ let kind = if frozen { RefKind :: Frozen } else { RefKind :: Raw } ;
580+ alloc. extra . reborrow ( cur_ptr, size, new_bor, kind)
581+ } ) ?;
582+ } else {
583+ // Just treat this as one big chunk.
584+ let kind = if new_bor. is_unique ( ) { RefKind :: Unique } else { RefKind :: Raw } ;
585+ alloc. extra . reborrow ( ptr, size, new_bor, kind) ?;
586+ }
587+ Ok ( new_ptr)
552588 }
553589
554- fn reborrow (
590+ fn retag_reference (
555591 & mut self ,
556592 val : ImmTy < ' tcx , Borrow > ,
557593 mutbl : Mutability ,
@@ -566,33 +602,17 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> {
566602 return Ok ( * val) ;
567603 }
568604
569- // Prepare to re-borrow this place.
570- let ptr = place. ptr . to_ptr ( ) ?;
605+ // Compute new borrow.
571606 let time = self . machine . stacked_borrows . increment_clock ( ) ;
572607 let new_bor = match mutbl {
573608 MutMutable => Borrow :: Uniq ( time) ,
574609 MutImmutable => Borrow :: Shr ( Some ( time) ) ,
575610 } ;
576- trace ! ( "reborrow: Creating new {:?} reference for {:?} (pointee {}): {:?}" ,
577- mutbl, ptr, place. layout. ty, new_bor) ;
578611
579- // Get the allocation. It might not be mutable, so we cannot use `get_mut`.
580- self . memory ( ) . check_bounds ( ptr, size, false ) ?;
581- let alloc = self . memory ( ) . get ( ptr. alloc_id ) . expect ( "We checked that the ptr is fine!" ) ;
582- // Update the stacks.
583- if mutbl == MutImmutable {
584- // Shared reference. We need a frozen-sensitive reborrow.
585- self . visit_freeze_sensitive ( place, size, |cur_ptr, size, frozen| {
586- let kind = if frozen { RefKind :: Frozen } else { RefKind :: Raw } ;
587- alloc. extra . reborrow ( cur_ptr, size, new_bor, kind)
588- } ) ?;
589- } else {
590- // Mutable reference. Just treat this as one big chunk.
591- alloc. extra . reborrow ( ptr, size, new_bor, RefKind :: Unique ) ?;
592- }
612+ // Reborrow.
613+ let new_ptr = self . reborrow ( place, size, new_bor) ?;
593614
594615 // Return new ptr
595- let new_ptr = Pointer :: new_with_tag ( ptr. alloc_id , ptr. offset , new_bor) ;
596616 let new_place = MemPlace { ptr : Scalar :: Ptr ( new_ptr) , ..* place } ;
597617 Ok ( new_place. to_ref ( ) )
598618 }
@@ -611,8 +631,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> {
611631 ty:: Ref ( _, _, mutbl) => {
612632 // fast path
613633 let val = self . read_immediate ( self . place_to_op ( place) ?) ?;
614- let val = self . reborrow ( val, mutbl) ?;
634+ let val = self . retag_reference ( val, mutbl) ?;
615635 self . write_immediate ( val, place) ?;
636+ return Ok ( ( ) ) ;
616637 }
617638 _ => { } , // handled with the general case below
618639 } ;
@@ -643,7 +664,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> {
643664 match place. layout . ty . sty {
644665 ty:: Ref ( _, _, mutbl) => {
645666 let val = self . ecx . read_immediate ( place. into ( ) ) ?;
646- let val = self . ecx . reborrow ( val, mutbl) ?;
667+ let val = self . ecx . retag_reference ( val, mutbl) ?;
647668 self . ecx . write_immediate ( val, place. into ( ) ) ?;
648669 }
649670 _ => { } , // nothing to do
0 commit comments