@@ -92,27 +92,90 @@ pub enum Permission {
9292 Disabled ,
9393}
9494
95- /// An item in the per-location borrow stack.
96- #[ derive( Copy , Clone , Hash , PartialEq , Eq ) ]
97- pub struct Item {
98- /// The permission this item grants.
99- perm : Permission ,
100- /// The pointers the permission is granted to.
101- tag : SbTag ,
102- /// An optional protector, ensuring the item cannot get popped until `CallId` is over.
103- protector : Option < CallId > ,
95+ impl Permission {
96+ fn to_bits ( self ) -> u64 {
97+ match self {
98+ Permission :: Unique => 0 ,
99+ Permission :: SharedReadWrite => 1 ,
100+ Permission :: SharedReadOnly => 2 ,
101+ Permission :: Disabled => 3 ,
102+ }
103+ }
104+
105+ fn from_bits ( perm : u64 ) -> Self {
106+ match perm {
107+ 0 => Permission :: Unique ,
108+ 1 => Permission :: SharedReadWrite ,
109+ 2 => Permission :: SharedReadOnly ,
110+ 3 => Permission :: Disabled ,
111+ _ => unreachable ! ( ) ,
112+ }
113+ }
104114}
105115
106- impl fmt:: Debug for Item {
107- fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
108- write ! ( f, "[{:?} for {:?}" , self . perm, self . tag) ?;
109- if let Some ( call) = self . protector {
110- write ! ( f, " (call {})" , call) ?;
116+ mod item {
117+ use super :: { Permission , SbTag } ;
118+ use std:: fmt;
119+
120+ /// An item in the per-location borrow stack.
121+ #[ derive( Copy , Clone , Hash , PartialEq , Eq ) ]
122+ pub struct Item ( u64 ) ;
123+
124+ // An Item contains 3 bitfields:
125+ // * Bits 0-61 store an SbTag
126+ // * Bits 61-63 store a Permission
127+ // * Bit 64 stores a flag which indicates if we have a protector
128+ const TAG_MASK : u64 = u64:: MAX >> 3 ;
129+ const PERM_MASK : u64 = 0x3 << 61 ;
130+ const PROTECTED_MASK : u64 = 0x1 << 63 ;
131+
132+ const PERM_SHIFT : u64 = 61 ;
133+ const PROTECTED_SHIFT : u64 = 63 ;
134+
135+ impl Item {
136+ pub fn new ( tag : SbTag , perm : Permission , protected : bool ) -> Self {
137+ assert ! ( tag. 0 . get( ) <= TAG_MASK ) ;
138+ let packed_tag = tag. 0 . get ( ) ;
139+ let packed_perm = perm. to_bits ( ) << PERM_SHIFT ;
140+ let packed_protected = ( protected as u64 ) << PROTECTED_SHIFT ;
141+
142+ let new = Self ( packed_tag + packed_perm + packed_protected) ;
143+
144+ debug_assert ! ( new. tag( ) == tag) ;
145+ debug_assert ! ( new. perm( ) == perm) ;
146+ debug_assert ! ( new. protected( ) == protected) ;
147+
148+ new
149+ }
150+
151+ /// The pointers the permission is granted to.
152+ pub fn tag ( self ) -> SbTag {
153+ unsafe { SbTag ( std:: num:: NonZeroU64 :: new_unchecked ( self . 0 & TAG_MASK ) ) }
154+ }
155+
156+ /// The permission this item grants.
157+ pub fn perm ( self ) -> Permission {
158+ Permission :: from_bits ( ( self . 0 & PERM_MASK ) >> PERM_SHIFT )
159+ }
160+
161+ /// Whether or not there is a protector for this tag
162+ pub fn protected ( self ) -> bool {
163+ self . 0 & PROTECTED_MASK > 0
164+ }
165+
166+ /// Set the Permission stored in this Item to Permission::Disabled
167+ pub fn set_disabled ( & mut self ) {
168+ self . 0 |= Permission :: Disabled . to_bits ( ) << PERM_SHIFT ;
169+ }
170+ }
171+
172+ impl fmt:: Debug for Item {
173+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
174+ write ! ( f, "[{:?} for {:?}]" , self . perm( ) , self . tag( ) )
111175 }
112- write ! ( f, "]" ) ?;
113- Ok ( ( ) )
114176 }
115177}
178+ pub use item:: Item ;
116179
117180/// Extra per-allocation state.
118181#[ derive( Clone , Debug ) ]
@@ -138,6 +201,8 @@ pub struct GlobalStateInner {
138201 next_call_id : CallId ,
139202 /// Those call IDs corresponding to functions that are still running.
140203 active_calls : FxHashSet < CallId > ,
204+ /// All tags currently protected
205+ pub ( crate ) protected_tags : FxHashMap < SbTag , CallId > ,
141206 /// The pointer ids to trace
142207 tracked_pointer_tags : HashSet < SbTag > ,
143208 /// The call ids to trace
@@ -202,6 +267,7 @@ impl GlobalStateInner {
202267 base_ptr_tags : FxHashMap :: default ( ) ,
203268 next_call_id : NonZeroU64 :: new ( 1 ) . unwrap ( ) ,
204269 active_calls : FxHashSet :: default ( ) ,
270+ protected_tags : FxHashMap :: default ( ) ,
205271 tracked_pointer_tags,
206272 tracked_call_ids,
207273 retag_fields,
@@ -230,10 +296,6 @@ impl GlobalStateInner {
230296 assert ! ( self . active_calls. remove( & id) ) ;
231297 }
232298
233- fn is_active ( & self , id : CallId ) -> bool {
234- self . active_calls . contains ( & id)
235- }
236-
237299 pub fn base_ptr_tag ( & mut self , id : AllocId ) -> SbTag {
238300 self . base_ptr_tags . get ( & id) . copied ( ) . unwrap_or_else ( || {
239301 let tag = self . new_ptr ( ) ;
@@ -287,7 +349,7 @@ impl<'tcx> Stack {
287349 /// Find the first write-incompatible item above the given one --
288350 /// i.e, find the height to which the stack will be truncated when writing to `granting`.
289351 fn find_first_write_incompatible ( & self , granting : usize ) -> usize {
290- let perm = self . get ( granting) . unwrap ( ) . perm ;
352+ let perm = self . get ( granting) . unwrap ( ) . perm ( ) ;
291353 match perm {
292354 Permission :: SharedReadOnly => bug ! ( "Cannot use SharedReadOnly for writing" ) ,
293355 Permission :: Disabled => bug ! ( "Cannot use Disabled for anything" ) ,
@@ -299,7 +361,7 @@ impl<'tcx> Stack {
299361 // The SharedReadWrite *just* above us are compatible, to skip those.
300362 let mut idx = granting + 1 ;
301363 while let Some ( item) = self . get ( idx) {
302- if item. perm == Permission :: SharedReadWrite {
364+ if item. perm ( ) == Permission :: SharedReadWrite {
303365 // Go on.
304366 idx += 1 ;
305367 } else {
@@ -326,31 +388,36 @@ impl<'tcx> Stack {
326388 global : & GlobalStateInner ,
327389 alloc_history : & mut AllocHistory ,
328390 ) -> InterpResult < ' tcx > {
329- if global. tracked_pointer_tags . contains ( & item. tag ) {
391+ if global. tracked_pointer_tags . contains ( & item. tag ( ) ) {
330392 register_diagnostic ( NonHaltingDiagnostic :: PoppedPointerTag (
331393 * item,
332394 provoking_access. map ( |( tag, _alloc_range, _size, access) | ( tag, access) ) ,
333395 ) ) ;
334396 }
335397
336- if let Some ( call) = item. protector {
337- if global. is_active ( call) {
338- if let Some ( ( tag, _alloc_range, _offset, _access) ) = provoking_access {
339- Err ( err_sb_ub (
340- format ! (
341- "not granting access to tag {:?} because incompatible item is protected: {:?}" ,
342- tag, item
343- ) ,
344- None ,
345- tag. and_then ( |tag| alloc_history. get_logs_relevant_to ( tag, Some ( item. tag ) ) ) ,
346- ) ) ?
347- } else {
348- Err ( err_sb_ub (
349- format ! ( "deallocating while item is protected: {:?}" , item) ,
350- None ,
351- None ,
352- ) ) ?
353- }
398+ if !item. protected ( ) {
399+ return Ok ( ( ) ) ;
400+ }
401+
402+ if let Some ( call_id) = global. protected_tags . get ( & item. tag ( ) ) {
403+ if let Some ( ( tag, _alloc_range, _offset, _access) ) = provoking_access {
404+ Err ( err_sb_ub (
405+ format ! (
406+ "not granting access to tag {:?} because incompatible item is protected: {:?} (call {:?})" ,
407+ tag, item, call_id
408+ ) ,
409+ None ,
410+ tag. and_then ( |tag| alloc_history. get_logs_relevant_to ( tag, Some ( item. tag ( ) ) ) ) ,
411+ ) ) ?
412+ } else {
413+ Err ( err_sb_ub (
414+ format ! (
415+ "deallocating while item is protected: {:?} (call {:?})" ,
416+ item, call_id
417+ ) ,
418+ None ,
419+ None ,
420+ ) ) ?
354421 }
355422 }
356423 Ok ( ( ) )
@@ -400,7 +467,7 @@ impl<'tcx> Stack {
400467 global,
401468 alloc_history,
402469 ) ?;
403- alloc_history. log_invalidation ( item. tag , alloc_range, current_span) ;
470+ alloc_history. log_invalidation ( item. tag ( ) , alloc_range, current_span) ;
404471 Ok ( ( ) )
405472 } ) ?;
406473 } else {
@@ -426,7 +493,7 @@ impl<'tcx> Stack {
426493 global,
427494 alloc_history,
428495 ) ?;
429- alloc_history. log_invalidation ( item. tag , alloc_range, current_span) ;
496+ alloc_history. log_invalidation ( item. tag ( ) , alloc_range, current_span) ;
430497 Ok ( ( ) )
431498 } ) ?;
432499 }
@@ -439,9 +506,9 @@ impl<'tcx> Stack {
439506 for i in 0 ..self . len ( ) {
440507 let item = self . get ( i) . unwrap ( ) ;
441508 // Skip disabled items, they cannot be matched anyway.
442- if !matches ! ( item. perm, Permission :: Disabled ) {
509+ if !matches ! ( item. perm( ) , Permission :: Disabled ) {
443510 // We are looking for a strict upper bound, so add 1 to this tag.
444- max = cmp:: max ( item. tag . 0 . checked_add ( 1 ) . unwrap ( ) , max) ;
511+ max = cmp:: max ( item. tag ( ) . 0 . checked_add ( 1 ) . unwrap ( ) , max) ;
445512 }
446513 }
447514 if let Some ( unk) = self . unknown_bottom ( ) {
@@ -505,7 +572,7 @@ impl<'tcx> Stack {
505572 ) -> InterpResult < ' tcx > {
506573 // Figure out which access `perm` corresponds to.
507574 let access =
508- if new. perm . grants ( AccessKind :: Write ) { AccessKind :: Write } else { AccessKind :: Read } ;
575+ if new. perm ( ) . grants ( AccessKind :: Write ) { AccessKind :: Write } else { AccessKind :: Read } ;
509576
510577 // Now we figure out which item grants our parent (`derived_from`) this kind of access.
511578 // We use that to determine where to put the new item.
@@ -517,7 +584,7 @@ impl<'tcx> Stack {
517584 // Compute where to put the new item.
518585 // Either way, we ensure that we insert the new item in a way such that between
519586 // `derived_from` and the new one, there are only items *compatible with* `derived_from`.
520- let new_idx = if new. perm == Permission :: SharedReadWrite {
587+ let new_idx = if new. perm ( ) == Permission :: SharedReadWrite {
521588 assert ! (
522589 access == AccessKind :: Write ,
523590 "this case only makes sense for stack-like accesses"
@@ -578,7 +645,7 @@ impl<'tcx> Stack {
578645impl < ' tcx > Stacks {
579646 /// Creates new stack with initial tag.
580647 fn new ( size : Size , perm : Permission , tag : SbTag ) -> Self {
581- let item = Item { perm, tag , protector : None } ;
648+ let item = Item :: new ( tag , perm, false ) ;
582649 let stack = Stack :: new ( item) ;
583650
584651 Stacks {
@@ -808,7 +875,6 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
808875 } ) ;
809876 }
810877
811- let protector = if protect { Some ( this. frame ( ) . extra . call_id ) } else { None } ;
812878 trace ! (
813879 "reborrow: {} reference {:?} derived from {:?} (pointee {}): {:?}, size {}" ,
814880 kind,
@@ -819,6 +885,22 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
819885 size. bytes( )
820886 ) ;
821887
888+ // FIXME: This just protects everything, which is wrong. At the very least, we should not
889+ // protect anything that contains an UnsafeCell.
890+ if protect {
891+ this. frame_mut ( ) . extra . protected_tags . push ( new_tag) ;
892+ let call_id = this. frame ( ) . extra . call_id ;
893+ this. machine
894+ . stacked_borrows
895+ . as_mut ( )
896+ . unwrap ( )
897+ . get_mut ( )
898+ . protected_tags
899+ . insert ( new_tag, call_id) ;
900+ }
901+ // FIXME: can't hold the current span handle across the borrows of self above
902+ let current_span = & mut this. machine . current_span ( ) ;
903+
822904 // Update the stacks.
823905 // Make sure that raw pointers and mutable shared references are reborrowed "weak":
824906 // There could be existing unique pointers reborrowed from them that should remain valid!
@@ -855,14 +937,14 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
855937 } else {
856938 Permission :: SharedReadWrite
857939 } ;
858- let protector = if frozen {
859- protector
940+ let protected = if frozen {
941+ protect
860942 } else {
861943 // We do not protect inside UnsafeCell.
862944 // This fixes https://github.com/rust-lang/rust/issues/55005.
863- None
945+ false
864946 } ;
865- let item = Item { perm , tag : new_tag, protector } ;
947+ let item = Item :: new ( new_tag, perm , protected ) ;
866948 let mut global = this. machine . stacked_borrows . as_ref ( ) . unwrap ( ) . borrow_mut ( ) ;
867949 stacked_borrows. for_each ( range, |offset, stack, history, exposed_tags| {
868950 stack. grant (
@@ -888,7 +970,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
888970 . as_mut ( )
889971 . expect ( "we should have Stacked Borrows data" )
890972 . borrow_mut ( ) ;
891- let item = Item { perm , tag : new_tag, protector } ;
973+ let item = Item :: new ( new_tag, perm , protect ) ;
892974 let range = alloc_range ( base_offset, size) ;
893975 let mut global = machine. stacked_borrows . as_ref ( ) . unwrap ( ) . borrow_mut ( ) ;
894976 let current_span = & mut machine. current_span ( ) ; // `get_alloc_extra_mut` invalidated our old `current_span`
0 commit comments