@@ -92,22 +92,90 @@ pub enum Permission {
92
92
Disabled ,
93
93
}
94
94
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
- /// Whether or not there is a protector for this tag
103
- protected : bool ,
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
+ }
104
114
}
105
115
106
- impl fmt:: Debug for Item {
107
- fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
108
- write ! ( f, "[{:?} for {:?}]" , self . perm, self . tag)
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( ) )
175
+ }
109
176
}
110
177
}
178
+ pub use item:: Item ;
111
179
112
180
/// Extra per-allocation state.
113
181
#[ derive( Clone , Debug ) ]
@@ -134,7 +202,7 @@ pub struct GlobalStateInner {
134
202
/// Those call IDs corresponding to functions that are still running.
135
203
active_calls : FxHashSet < CallId > ,
136
204
/// All tags currently protected
137
- pub ( crate ) protected_tags : FxHashSet < SbTag > ,
205
+ pub ( crate ) protected_tags : FxHashMap < SbTag , CallId > ,
138
206
/// The pointer ids to trace
139
207
tracked_pointer_tags : HashSet < SbTag > ,
140
208
/// The call ids to trace
@@ -199,7 +267,7 @@ impl GlobalStateInner {
199
267
base_ptr_tags : FxHashMap :: default ( ) ,
200
268
next_call_id : NonZeroU64 :: new ( 1 ) . unwrap ( ) ,
201
269
active_calls : FxHashSet :: default ( ) ,
202
- protected_tags : FxHashSet :: default ( ) ,
270
+ protected_tags : FxHashMap :: default ( ) ,
203
271
tracked_pointer_tags,
204
272
tracked_call_ids,
205
273
retag_fields,
@@ -281,7 +349,7 @@ impl<'tcx> Stack {
281
349
/// Find the first write-incompatible item above the given one --
282
350
/// i.e, find the height to which the stack will be truncated when writing to `granting`.
283
351
fn find_first_write_incompatible ( & self , granting : usize ) -> usize {
284
- let perm = self . get ( granting) . unwrap ( ) . perm ;
352
+ let perm = self . get ( granting) . unwrap ( ) . perm ( ) ;
285
353
match perm {
286
354
Permission :: SharedReadOnly => bug ! ( "Cannot use SharedReadOnly for writing" ) ,
287
355
Permission :: Disabled => bug ! ( "Cannot use Disabled for anything" ) ,
@@ -293,7 +361,7 @@ impl<'tcx> Stack {
293
361
// The SharedReadWrite *just* above us are compatible, to skip those.
294
362
let mut idx = granting + 1 ;
295
363
while let Some ( item) = self . get ( idx) {
296
- if item. perm == Permission :: SharedReadWrite {
364
+ if item. perm ( ) == Permission :: SharedReadWrite {
297
365
// Go on.
298
366
idx += 1 ;
299
367
} else {
@@ -320,26 +388,33 @@ impl<'tcx> Stack {
320
388
global : & GlobalStateInner ,
321
389
alloc_history : & mut AllocHistory ,
322
390
) -> InterpResult < ' tcx > {
323
- if global. tracked_pointer_tags . contains ( & item. tag ) {
391
+ if global. tracked_pointer_tags . contains ( & item. tag ( ) ) {
324
392
register_diagnostic ( NonHaltingDiagnostic :: PoppedPointerTag (
325
393
* item,
326
394
provoking_access. map ( |( tag, _alloc_range, _size, access) | ( tag, access) ) ,
327
395
) ) ;
328
396
}
329
397
330
- if item. protected && global. protected_tags . contains ( & item. tag ) {
398
+ if !item. protected ( ) {
399
+ return Ok ( ( ) ) ;
400
+ }
401
+
402
+ if let Some ( call_id) = global. protected_tags . get ( & item. tag ( ) ) {
331
403
if let Some ( ( tag, _alloc_range, _offset, _access) ) = provoking_access {
332
404
Err ( err_sb_ub (
333
405
format ! (
334
- "not granting access to tag {:?} because incompatible item is protected: {:?}" ,
335
- tag, item
406
+ "not granting access to tag {:?} because incompatible item is protected: {:?} (call {:?}) " ,
407
+ tag, item, call_id
336
408
) ,
337
409
None ,
338
- tag. and_then ( |tag| alloc_history. get_logs_relevant_to ( tag, Some ( item. tag ) ) ) ,
410
+ tag. and_then ( |tag| alloc_history. get_logs_relevant_to ( tag, Some ( item. tag ( ) ) ) ) ,
339
411
) ) ?
340
412
} else {
341
413
Err ( err_sb_ub (
342
- format ! ( "deallocating while item is protected: {:?}" , item) ,
414
+ format ! (
415
+ "deallocating while item is protected: {:?} (call {:?})" ,
416
+ item, call_id
417
+ ) ,
343
418
None ,
344
419
None ,
345
420
) ) ?
@@ -392,7 +467,7 @@ impl<'tcx> Stack {
392
467
global,
393
468
alloc_history,
394
469
) ?;
395
- alloc_history. log_invalidation ( item. tag , alloc_range, current_span) ;
470
+ alloc_history. log_invalidation ( item. tag ( ) , alloc_range, current_span) ;
396
471
Ok ( ( ) )
397
472
} ) ?;
398
473
} else {
@@ -418,7 +493,7 @@ impl<'tcx> Stack {
418
493
global,
419
494
alloc_history,
420
495
) ?;
421
- alloc_history. log_invalidation ( item. tag , alloc_range, current_span) ;
496
+ alloc_history. log_invalidation ( item. tag ( ) , alloc_range, current_span) ;
422
497
Ok ( ( ) )
423
498
} ) ?;
424
499
}
@@ -431,9 +506,9 @@ impl<'tcx> Stack {
431
506
for i in 0 ..self . len ( ) {
432
507
let item = self . get ( i) . unwrap ( ) ;
433
508
// Skip disabled items, they cannot be matched anyway.
434
- if !matches ! ( item. perm, Permission :: Disabled ) {
509
+ if !matches ! ( item. perm( ) , Permission :: Disabled ) {
435
510
// We are looking for a strict upper bound, so add 1 to this tag.
436
- max = cmp:: max ( item. tag . 0 . checked_add ( 1 ) . unwrap ( ) , max) ;
511
+ max = cmp:: max ( item. tag ( ) . 0 . checked_add ( 1 ) . unwrap ( ) , max) ;
437
512
}
438
513
}
439
514
if let Some ( unk) = self . unknown_bottom ( ) {
@@ -497,7 +572,7 @@ impl<'tcx> Stack {
497
572
) -> InterpResult < ' tcx > {
498
573
// Figure out which access `perm` corresponds to.
499
574
let access =
500
- if new. perm . grants ( AccessKind :: Write ) { AccessKind :: Write } else { AccessKind :: Read } ;
575
+ if new. perm ( ) . grants ( AccessKind :: Write ) { AccessKind :: Write } else { AccessKind :: Read } ;
501
576
502
577
// Now we figure out which item grants our parent (`derived_from`) this kind of access.
503
578
// We use that to determine where to put the new item.
@@ -509,7 +584,7 @@ impl<'tcx> Stack {
509
584
// Compute where to put the new item.
510
585
// Either way, we ensure that we insert the new item in a way such that between
511
586
// `derived_from` and the new one, there are only items *compatible with* `derived_from`.
512
- let new_idx = if new. perm == Permission :: SharedReadWrite {
587
+ let new_idx = if new. perm ( ) == Permission :: SharedReadWrite {
513
588
assert ! (
514
589
access == AccessKind :: Write ,
515
590
"this case only makes sense for stack-like accesses"
@@ -570,7 +645,7 @@ impl<'tcx> Stack {
570
645
impl < ' tcx > Stacks {
571
646
/// Creates new stack with initial tag.
572
647
fn new ( size : Size , perm : Permission , tag : SbTag ) -> Self {
573
- let item = Item { perm, tag , protected : false } ;
648
+ let item = Item :: new ( tag , perm, false ) ;
574
649
let stack = Stack :: new ( item) ;
575
650
576
651
Stacks {
@@ -814,7 +889,14 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
814
889
// protect anything that contains an UnsafeCell.
815
890
if protect {
816
891
this. frame_mut ( ) . extra . protected_tags . push ( new_tag) ;
817
- this. machine . stacked_borrows . as_mut ( ) . unwrap ( ) . get_mut ( ) . protected_tags . insert ( 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) ;
818
900
}
819
901
// FIXME: can't hold the current span handle across the borrows of self above
820
902
let current_span = & mut this. machine . current_span ( ) ;
@@ -862,7 +944,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
862
944
// This fixes https://github.com/rust-lang/rust/issues/55005.
863
945
false
864
946
} ;
865
- let item = Item { perm , tag : new_tag, protected } ;
947
+ let item = Item :: new ( new_tag, perm , protected ) ;
866
948
let mut global = this. machine . stacked_borrows . as_ref ( ) . unwrap ( ) . borrow_mut ( ) ;
867
949
stacked_borrows. for_each ( range, |offset, stack, history, exposed_tags| {
868
950
stack. grant (
@@ -888,7 +970,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
888
970
. as_mut ( )
889
971
. expect ( "we should have Stacked Borrows data" )
890
972
. borrow_mut ( ) ;
891
- let item = Item { perm , tag : new_tag, protected : protect } ;
973
+ let item = Item :: new ( new_tag, perm , protect) ;
892
974
let range = alloc_range ( base_offset, size) ;
893
975
let mut global = machine. stacked_borrows . as_ref ( ) . unwrap ( ) . borrow_mut ( ) ;
894
976
let current_span = & mut machine. current_span ( ) ; // `get_alloc_extra_mut` invalidated our old `current_span`
0 commit comments