@@ -303,6 +303,9 @@ impl<'tcx> Stacks {
303
303
trace ! ( "{} access of tag {:?}: {:?}, size {}" ,
304
304
if is_write { "read" } else { "write" } ,
305
305
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.
306
309
let mut stacks = self . stacks . borrow_mut ( ) ;
307
310
for stack in stacks. iter_mut ( ptr. offset , size) {
308
311
stack. access ( ptr. tag , is_write) ?;
@@ -311,6 +314,7 @@ impl<'tcx> Stacks {
311
314
}
312
315
313
316
/// 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.
314
318
fn reborrow (
315
319
& self ,
316
320
ptr : Pointer < Borrow > ,
@@ -414,8 +418,16 @@ pub trait EvalContextExt<'tcx> {
414
418
kind : MemoryKind < MiriMemoryKind > ,
415
419
) -> Borrow ;
416
420
417
- /// Retag an indidual pointer , returning the retagged version .
421
+ /// Reborrow the given place , returning the newly tagged ptr to it .
418
422
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 (
419
431
& mut self ,
420
432
ptr : ImmTy < ' tcx , Borrow > ,
421
433
mutbl : Mutability ,
@@ -536,22 +548,46 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> {
536
548
}
537
549
538
550
/// The given place may henceforth be accessed through raw pointers.
551
+ #[ inline( always) ]
539
552
fn escape_to_raw (
540
553
& mut self ,
541
554
place : MPlaceTy < ' tcx , Borrow > ,
542
555
size : Size ,
543
556
) -> 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 > > {
546
567
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 ) ?;
548
574
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)
552
588
}
553
589
554
- fn reborrow (
590
+ fn retag_reference (
555
591
& mut self ,
556
592
val : ImmTy < ' tcx , Borrow > ,
557
593
mutbl : Mutability ,
@@ -566,33 +602,17 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> {
566
602
return Ok ( * val) ;
567
603
}
568
604
569
- // Prepare to re-borrow this place.
570
- let ptr = place. ptr . to_ptr ( ) ?;
605
+ // Compute new borrow.
571
606
let time = self . machine . stacked_borrows . increment_clock ( ) ;
572
607
let new_bor = match mutbl {
573
608
MutMutable => Borrow :: Uniq ( time) ,
574
609
MutImmutable => Borrow :: Shr ( Some ( time) ) ,
575
610
} ;
576
- trace ! ( "reborrow: Creating new {:?} reference for {:?} (pointee {}): {:?}" ,
577
- mutbl, ptr, place. layout. ty, new_bor) ;
578
611
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) ?;
593
614
594
615
// Return new ptr
595
- let new_ptr = Pointer :: new_with_tag ( ptr. alloc_id , ptr. offset , new_bor) ;
596
616
let new_place = MemPlace { ptr : Scalar :: Ptr ( new_ptr) , ..* place } ;
597
617
Ok ( new_place. to_ref ( ) )
598
618
}
@@ -611,8 +631,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> {
611
631
ty:: Ref ( _, _, mutbl) => {
612
632
// fast path
613
633
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) ?;
615
635
self . write_immediate ( val, place) ?;
636
+ return Ok ( ( ) ) ;
616
637
}
617
638
_ => { } , // handled with the general case below
618
639
} ;
@@ -643,7 +664,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> {
643
664
match place. layout . ty . sty {
644
665
ty:: Ref ( _, _, mutbl) => {
645
666
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) ?;
647
668
self . ecx . write_immediate ( val, place. into ( ) ) ?;
648
669
}
649
670
_ => { } , // nothing to do
0 commit comments