@@ -23,6 +23,10 @@ use crate::*;
2323pub mod diagnostics;
2424use diagnostics:: { AllocHistory , TagHistory } ;
2525
26+ pub mod stack;
27+ use stack:: Stack ;
28+
29+ pub type PtrId = NonZeroU64 ;
2630pub type CallId = NonZeroU64 ;
2731
2832// Even reading memory can have effects on the stack, so we need a `RefCell` here.
@@ -111,23 +115,6 @@ impl fmt::Debug for Item {
111115 }
112116}
113117
114- /// Extra per-location state.
115- #[ derive( Clone , Debug , PartialEq , Eq ) ]
116- pub struct Stack {
117- /// Used *mostly* as a stack; never empty.
118- /// Invariants:
119- /// * Above a `SharedReadOnly` there can only be more `SharedReadOnly`.
120- /// * No tag occurs in the stack more than once.
121- borrows : Vec < Item > ,
122- /// If this is `Some(id)`, then the actual current stack is unknown. This can happen when
123- /// wildcard pointers are used to access this location. What we do know is that `borrows` are at
124- /// the top of the stack, and below it are arbitrarily many items whose `tag` is strictly less
125- /// than `id`.
126- /// When the bottom is unknown, `borrows` always has a `SharedReadOnly` or `Unique` at the bottom;
127- /// we never have the unknown-to-known boundary in an SRW group.
128- unknown_bottom : Option < SbTag > ,
129- }
130-
131118/// Extra per-allocation state.
132119#[ derive( Clone , Debug ) ]
133120pub struct Stacks {
@@ -297,65 +284,10 @@ impl Permission {
297284
298285/// Core per-location operations: access, dealloc, reborrow.
299286impl < ' tcx > Stack {
300- /// Find the item granting the given kind of access to the given tag, and return where
301- /// it is on the stack. For wildcard tags, the given index is approximate, but if *no*
302- /// index is given it means the match was *not* in the known part of the stack.
303- /// `Ok(None)` indicates it matched the "unknown" part of the stack.
304- /// `Err` indicates it was not found.
305- fn find_granting (
306- & self ,
307- access : AccessKind ,
308- tag : SbTagExtra ,
309- exposed_tags : & FxHashSet < SbTag > ,
310- ) -> Result < Option < usize > , ( ) > {
311- let SbTagExtra :: Concrete ( tag) = tag else {
312- // Handle the wildcard case.
313- // Go search the stack for an exposed tag.
314- if let Some ( idx) =
315- self . borrows
316- . iter ( )
317- . enumerate ( ) // we also need to know *where* in the stack
318- . rev ( ) // search top-to-bottom
319- . find_map ( |( idx, item) | {
320- // If the item fits and *might* be this wildcard, use it.
321- if item. perm . grants ( access) && exposed_tags. contains ( & item. tag ) {
322- Some ( idx)
323- } else {
324- None
325- }
326- } )
327- {
328- return Ok ( Some ( idx) ) ;
329- }
330- // If we couldn't find it in the stack, check the unknown bottom.
331- return if self . unknown_bottom . is_some ( ) { Ok ( None ) } else { Err ( ( ) ) } ;
332- } ;
333-
334- if let Some ( idx) =
335- self . borrows
336- . iter ( )
337- . enumerate ( ) // we also need to know *where* in the stack
338- . rev ( ) // search top-to-bottom
339- // Return permission of first item that grants access.
340- // We require a permission with the right tag, ensuring U3 and F3.
341- . find_map ( |( idx, item) | {
342- if tag == item. tag && item. perm . grants ( access) { Some ( idx) } else { None }
343- } )
344- {
345- return Ok ( Some ( idx) ) ;
346- }
347-
348- // Couldn't find it in the stack; but if there is an unknown bottom it might be there.
349- let found = self . unknown_bottom . is_some_and ( |& unknown_limit| {
350- tag. 0 < unknown_limit. 0 // unknown_limit is an upper bound for what can be in the unknown bottom.
351- } ) ;
352- if found { Ok ( None ) } else { Err ( ( ) ) }
353- }
354-
355287 /// Find the first write-incompatible item above the given one --
356288 /// i.e, find the height to which the stack will be truncated when writing to `granting`.
357289 fn find_first_write_incompatible ( & self , granting : usize ) -> usize {
358- let perm = self . borrows [ granting] . perm ;
290+ let perm = self . get ( granting) . unwrap ( ) . perm ;
359291 match perm {
360292 Permission :: SharedReadOnly => bug ! ( "Cannot use SharedReadOnly for writing" ) ,
361293 Permission :: Disabled => bug ! ( "Cannot use Disabled for anything" ) ,
@@ -366,7 +298,7 @@ impl<'tcx> Stack {
366298 Permission :: SharedReadWrite => {
367299 // The SharedReadWrite *just* above us are compatible, to skip those.
368300 let mut idx = granting + 1 ;
369- while let Some ( item) = self . borrows . get ( idx) {
301+ while let Some ( item) = self . get ( idx) {
370302 if item. perm == Permission :: SharedReadWrite {
371303 // Go on.
372304 idx += 1 ;
@@ -461,16 +393,16 @@ impl<'tcx> Stack {
461393 // There is a SRW group boundary between the unknown and the known, so everything is incompatible.
462394 0
463395 } ;
464- for item in self . borrows . drain ( first_incompatible_idx..) . rev ( ) {
465- trace ! ( "access: popping item {:?}" , item) ;
396+ self . pop_items_after ( first_incompatible_idx, |item| {
466397 Stack :: item_popped (
467398 & item,
468399 Some ( ( tag, alloc_range, offset, access) ) ,
469400 global,
470401 alloc_history,
471402 ) ?;
472403 alloc_history. log_invalidation ( item. tag , alloc_range, current_span) ;
473- }
404+ Ok ( ( ) )
405+ } ) ?;
474406 } else {
475407 // On a read, *disable* all `Unique` above the granting item. This ensures U2 for read accesses.
476408 // The reason this is not following the stack discipline (by removing the first Unique and
@@ -487,44 +419,39 @@ impl<'tcx> Stack {
487419 // We are reading from something in the unknown part. That means *all* `Unique` we know about are dead now.
488420 0
489421 } ;
490- for idx in ( first_incompatible_idx..self . borrows . len ( ) ) . rev ( ) {
491- let item = & mut self . borrows [ idx] ;
492-
493- if item. perm == Permission :: Unique {
494- trace ! ( "access: disabling item {:?}" , item) ;
495- Stack :: item_popped (
496- item,
497- Some ( ( tag, alloc_range, offset, access) ) ,
498- global,
499- alloc_history,
500- ) ?;
501- item. perm = Permission :: Disabled ;
502- alloc_history. log_invalidation ( item. tag , alloc_range, current_span) ;
503- }
504- }
422+ self . disable_uniques_starting_at ( first_incompatible_idx, |item| {
423+ Stack :: item_popped (
424+ & item,
425+ Some ( ( tag, alloc_range, offset, access) ) ,
426+ global,
427+ alloc_history,
428+ ) ?;
429+ alloc_history. log_invalidation ( item. tag , alloc_range, current_span) ;
430+ Ok ( ( ) )
431+ } ) ?;
505432 }
506433
507434 // If this was an approximate action, we now collapse everything into an unknown.
508435 if granting_idx. is_none ( ) || matches ! ( tag, SbTagExtra :: Wildcard ) {
509436 // Compute the upper bound of the items that remain.
510437 // (This is why we did all the work above: to reduce the items we have to consider here.)
511438 let mut max = NonZeroU64 :: new ( 1 ) . unwrap ( ) ;
512- for item in & self . borrows {
439+ for i in 0 ..self . len ( ) {
440+ let item = self . get ( i) . unwrap ( ) ;
513441 // Skip disabled items, they cannot be matched anyway.
514442 if !matches ! ( item. perm, Permission :: Disabled ) {
515443 // We are looking for a strict upper bound, so add 1 to this tag.
516444 max = cmp:: max ( item. tag . 0 . checked_add ( 1 ) . unwrap ( ) , max) ;
517445 }
518446 }
519- if let Some ( unk) = self . unknown_bottom {
447+ if let Some ( unk) = self . unknown_bottom ( ) {
520448 max = cmp:: max ( unk. 0 , max) ;
521449 }
522450 // Use `max` as new strict upper bound for everything.
523451 trace ! (
524452 "access: forgetting stack to upper bound {max} due to wildcard or unknown access"
525453 ) ;
526- self . borrows . clear ( ) ;
527- self . unknown_bottom = Some ( SbTag ( max) ) ;
454+ self . set_unknown_bottom ( SbTag ( max) ) ;
528455 }
529456
530457 // Done.
@@ -553,7 +480,8 @@ impl<'tcx> Stack {
553480 } ) ?;
554481
555482 // Step 2: Remove all items. Also checks for protectors.
556- for item in self . borrows . drain ( ..) . rev ( ) {
483+ for idx in ( 0 ..self . len ( ) ) . rev ( ) {
484+ let item = self . get ( idx) . unwrap ( ) ;
557485 Stack :: item_popped ( & item, None , global, alloc_history) ?;
558486 }
559487 Ok ( ( ) )
@@ -601,8 +529,7 @@ impl<'tcx> Stack {
601529 // The new thing is SRW anyway, so we cannot push it "on top of the unkown part"
602530 // (for all we know, it might join an SRW group inside the unknown).
603531 trace ! ( "reborrow: forgetting stack entirely due to SharedReadWrite reborrow from wildcard or unknown" ) ;
604- self . borrows . clear ( ) ;
605- self . unknown_bottom = Some ( global. next_ptr_tag ) ;
532+ self . set_unknown_bottom ( global. next_ptr_tag ) ;
606533 return Ok ( ( ) ) ;
607534 } ;
608535
@@ -629,19 +556,18 @@ impl<'tcx> Stack {
629556 // on top of `derived_from`, and we want the new item at the top so that we
630557 // get the strongest possible guarantees.
631558 // This ensures U1 and F1.
632- self . borrows . len ( )
559+ self . len ( )
633560 } ;
634561
635562 // Put the new item there. As an optimization, deduplicate if it is equal to one of its new neighbors.
636563 // `new_idx` might be 0 if we just cleared the entire stack.
637- if self . borrows . get ( new_idx) == Some ( & new)
638- || ( new_idx > 0 && self . borrows [ new_idx - 1 ] == new)
564+ if self . get ( new_idx) == Some ( new) || ( new_idx > 0 && self . get ( new_idx - 1 ) . unwrap ( ) == new)
639565 {
640566 // Optimization applies, done.
641567 trace ! ( "reborrow: avoiding adding redundant item {:?}" , new) ;
642568 } else {
643569 trace ! ( "reborrow: adding item {:?}" , new) ;
644- self . borrows . insert ( new_idx, new) ;
570+ self . insert ( new_idx, new) ;
645571 }
646572 Ok ( ( ) )
647573 }
@@ -653,8 +579,8 @@ impl<'tcx> Stacks {
653579 /// Creates new stack with initial tag.
654580 fn new ( size : Size , perm : Permission , tag : SbTag ) -> Self {
655581 let item = Item { perm, tag, protector : None } ;
656- let stack = Stack { borrows : vec ! [ item] , unknown_bottom : None } ;
657582
583+ let stack = Stack :: new ( item) ;
658584 Stacks {
659585 stacks : RangeMap :: new ( size, stack) ,
660586 history : AllocHistory :: new ( ) ,
@@ -900,11 +826,14 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
900826 // We have to use shared references to alloc/memory_extra here since
901827 // `visit_freeze_sensitive` needs to access the global state.
902828 let extra = this. get_alloc_extra ( alloc_id) ?;
829+
903830 let mut stacked_borrows = extra
904831 . stacked_borrows
905832 . as_ref ( )
906833 . expect ( "we should have Stacked Borrows data" )
907834 . borrow_mut ( ) ;
835+ let mut current_span = this. machine . current_span ( ) ;
836+
908837 this. visit_freeze_sensitive ( place, size, |mut range, frozen| {
909838 // Adjust range.
910839 range. start += base_offset;
@@ -929,7 +858,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
929858 item,
930859 ( alloc_id, range, offset) ,
931860 & mut global,
932- current_span,
861+ & mut current_span,
933862 history,
934863 exposed_tags,
935864 )
0 commit comments