@@ -125,81 +125,64 @@ pub struct NewPermission {
125
125
/// Whether a read access should be performed on the non-frozen
126
126
/// part on a retag.
127
127
nonfreeze_access : bool ,
128
+ /// Permission for memory outside the range.
129
+ outside_perm : Permission ,
128
130
/// Whether this pointer is part of the arguments of a function call.
129
131
/// `protector` is `Some(_)` for all pointers marked `noalias`.
130
132
protector : Option < ProtectorKind > ,
131
133
}
132
134
133
135
impl < ' tcx > NewPermission {
134
- /// Determine NewPermission of the reference from the type of the pointee.
135
- fn from_ref_ty (
136
+ /// Determine NewPermission of the reference/Box from the type of the pointee.
137
+ ///
138
+ /// A `ref_mutability` of `None` indicates a `Box` type.
139
+ fn new (
136
140
pointee : Ty < ' tcx > ,
137
- mutability : Mutability ,
138
- kind : RetagKind ,
141
+ ref_mutability : Option < Mutability > ,
142
+ retag_kind : RetagKind ,
139
143
cx : & crate :: MiriInterpCx < ' tcx > ,
140
144
) -> Option < Self > {
141
145
let ty_is_unpin = pointee. is_unpin ( * cx. tcx , cx. typing_env ( ) ) ;
142
- let is_protected = kind == RetagKind :: FnEntry ;
143
- let protector = is_protected. then_some ( ProtectorKind :: StrongProtector ) ;
144
-
145
- Some ( match mutability {
146
- Mutability :: Mut if ty_is_unpin =>
147
- NewPermission {
148
- freeze_perm : Permission :: new_reserved (
149
- /* ty_is_freeze */ true ,
150
- is_protected,
151
- ) ,
152
- freeze_access : true ,
153
- nonfreeze_perm : Permission :: new_reserved (
154
- /* ty_is_freeze */ false ,
155
- is_protected,
156
- ) ,
157
- // If we have a mutable reference, then the non-frozen part will
158
- // have state `ReservedIM` or `Reserved`, which can have an initial read access
159
- // performed on it because you cannot have multiple mutable borrows.
160
- nonfreeze_access : true ,
161
- protector,
162
- } ,
163
- Mutability :: Not =>
164
- NewPermission {
165
- freeze_perm : Permission :: new_frozen ( ) ,
166
- freeze_access : true ,
167
- nonfreeze_perm : Permission :: new_cell ( ) ,
168
- // If it is a shared reference, then the non-frozen
169
- // part will have state `Cell`, which should not have an initial access,
170
- // as this can cause data races when using thread-safe data types like
171
- // `Mutex<T>`.
172
- nonfreeze_access : false ,
173
- protector,
174
- } ,
175
- _ => return None ,
176
- } )
177
- }
146
+ let ty_is_freeze = pointee. is_freeze ( * cx. tcx , cx. typing_env ( ) ) ;
147
+ let is_protected = retag_kind == RetagKind :: FnEntry ;
178
148
179
- /// Compute permission for `Box`-like type (`Box` always, and also `Unique` if enabled).
180
- /// These pointers allow deallocation so need a different kind of protector not handled
181
- /// by `from_ref_ty`.
182
- fn from_unique_ty (
183
- ty : Ty < ' tcx > ,
184
- kind : RetagKind ,
185
- cx : & crate :: MiriInterpCx < ' tcx > ,
186
- ) -> Option < Self > {
187
- let pointee = ty. builtin_deref ( true ) . unwrap ( ) ;
188
- pointee. is_unpin ( * cx. tcx , cx. typing_env ( ) ) . then_some ( ( ) ) . map ( |( ) | {
189
- // Regular `Unpin` box, give it `noalias` but only a weak protector
190
- // because it is valid to deallocate it within the function.
191
- let is_protected = kind == RetagKind :: FnEntry ;
192
- let protector = is_protected. then_some ( ProtectorKind :: WeakProtector ) ;
193
- NewPermission {
194
- freeze_perm : Permission :: new_reserved ( /* ty_is_freeze */ true , is_protected) ,
195
- freeze_access : true ,
196
- nonfreeze_perm : Permission :: new_reserved (
197
- /* ty_is_freeze */ false ,
198
- is_protected,
199
- ) ,
200
- nonfreeze_access : true ,
201
- protector,
202
- }
149
+ if matches ! ( ref_mutability, Some ( Mutability :: Mut ) | None if !ty_is_unpin) {
150
+ // Mutable reference / Box to pinning type: retagging is a NOP.
151
+ // FIXME: with `UnsafePinned`, this should do proper per-byte tracking.
152
+ return None ;
153
+ }
154
+
155
+ let freeze_perm = match ref_mutability {
156
+ // Shared references are frozen.
157
+ Some ( Mutability :: Not ) => Permission :: new_frozen ( ) ,
158
+ // Mutable references and Boxes are reserved.
159
+ _ => Permission :: new_reserved_frz ( ) ,
160
+ } ;
161
+ let nonfreeze_perm = match ref_mutability {
162
+ // Shared references are "transparent".
163
+ Some ( Mutability :: Not ) => Permission :: new_cell ( ) ,
164
+ // *Protected* mutable references and boxes are reserved without regarding for interior mutability.
165
+ _ if is_protected => Permission :: new_reserved_frz ( ) ,
166
+ // Unprotected mutable references and boxes start in `ReservedIm`.
167
+ _ => Permission :: new_reserved_im ( ) ,
168
+ } ;
169
+
170
+ // Everything except for `Cell` gets an initial access.
171
+ let initial_access = |perm : & Permission | !perm. is_cell ( ) ;
172
+
173
+ Some ( NewPermission {
174
+ freeze_perm,
175
+ freeze_access : initial_access ( & freeze_perm) ,
176
+ nonfreeze_perm,
177
+ nonfreeze_access : initial_access ( & nonfreeze_perm) ,
178
+ outside_perm : if ty_is_freeze { freeze_perm } else { nonfreeze_perm } ,
179
+ protector : is_protected. then_some ( if ref_mutability. is_some ( ) {
180
+ // Strong protector for references
181
+ ProtectorKind :: StrongProtector
182
+ } else {
183
+ // Weak protector for boxes
184
+ ProtectorKind :: WeakProtector
185
+ } ) ,
203
186
} )
204
187
}
205
188
}
@@ -313,15 +296,11 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
313
296
314
297
let span = this. machine . current_span ( ) ;
315
298
316
- // Store initial permissions and their corresponding range .
299
+ // Store initial permissions for the "inside" part .
317
300
let mut perms_map: DedupRangeMap < LocationState > = DedupRangeMap :: new (
318
301
ptr_size,
319
302
LocationState :: new_accessed ( Permission :: new_disabled ( ) , IdempotentForeignAccess :: None ) , // this will be overwritten
320
303
) ;
321
- // Keep track of whether the node has any part that allows for interior mutability.
322
- // FIXME: This misses `PhantomData<UnsafeCell<T>>` which could be considered a marker
323
- // for requesting interior mutability.
324
- let mut has_unsafe_cell = false ;
325
304
326
305
// When adding a new node, the SIFA of its parents needs to be updated, potentially across
327
306
// the entire memory range. For the parts that are being accessed below, the access itself
@@ -350,14 +329,13 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
350
329
. get_tree_borrows_params ( )
351
330
. precise_interior_mut ;
352
331
353
- let default_perm = if !precise_interior_mut {
354
- // NOTE: Using `ty_is_freeze` doesn't give the same result as going through the range
355
- // and computing `has_unsafe_cell`. This is because of zero-sized `UnsafeCell`, for which
356
- // `has_unsafe_cell` is false, but `!ty_is_freeze` is true.
332
+ // Set "inside" permissions.
333
+ if !precise_interior_mut {
357
334
let ty_is_freeze = place. layout . ty . is_freeze ( * this. tcx , this. typing_env ( ) ) ;
358
335
let ( perm, access) = if ty_is_freeze {
359
336
( new_perm. freeze_perm , new_perm. freeze_access )
360
337
} else {
338
+ // Just pretend the entire thing is an `UnsafeCell`.
361
339
( new_perm. nonfreeze_perm , new_perm. nonfreeze_access )
362
340
} ;
363
341
let sifa = perm. strongest_idempotent_foreign_access ( protected) ;
@@ -370,12 +348,8 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
370
348
for ( _loc_range, loc) in perms_map. iter_mut_all ( ) {
371
349
* loc = new_loc;
372
350
}
373
-
374
- perm
375
351
} else {
376
352
this. visit_freeze_sensitive ( place, ptr_size, |range, frozen| {
377
- has_unsafe_cell = has_unsafe_cell || !frozen;
378
-
379
353
// We are only ever `Frozen` inside the frozen bits.
380
354
let ( perm, access) = if frozen {
381
355
( new_perm. freeze_perm , new_perm. freeze_access )
@@ -401,9 +375,6 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
401
375
402
376
interp_ok ( ( ) )
403
377
} ) ?;
404
-
405
- // Allow lazily writing to surrounding data if we found an `UnsafeCell`.
406
- if has_unsafe_cell { new_perm. nonfreeze_perm } else { new_perm. freeze_perm }
407
378
} ;
408
379
409
380
let alloc_extra = this. get_alloc_extra ( alloc_id) ?;
@@ -447,7 +418,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
447
418
orig_tag,
448
419
new_tag,
449
420
perms_map,
450
- default_perm ,
421
+ new_perm . outside_perm ,
451
422
protected,
452
423
span,
453
424
) ?;
@@ -514,7 +485,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
514
485
let this = self . eval_context_mut ( ) ;
515
486
let new_perm = match val. layout . ty . kind ( ) {
516
487
& ty:: Ref ( _, pointee, mutability) =>
517
- NewPermission :: from_ref_ty ( pointee, mutability, kind, this) ,
488
+ NewPermission :: new ( pointee, Some ( mutability) , kind, this) ,
518
489
_ => None ,
519
490
} ;
520
491
if let Some ( new_perm) = new_perm {
@@ -571,8 +542,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
571
542
fn visit_box ( & mut self , box_ty : Ty < ' tcx > , place : & PlaceTy < ' tcx > ) -> InterpResult < ' tcx > {
572
543
// Only boxes for the global allocator get any special treatment.
573
544
if box_ty. is_box_global ( * self . ecx . tcx ) {
545
+ let pointee = place. layout . ty . builtin_deref ( true ) . unwrap ( ) ;
574
546
let new_perm =
575
- NewPermission :: from_unique_ty ( place . layout . ty , self . kind , self . ecx ) ;
547
+ NewPermission :: new ( pointee , /* not a ref */ None , self . kind , self . ecx ) ;
576
548
self . retag_ptr_inplace ( place, new_perm) ?;
577
549
}
578
550
interp_ok ( ( ) )
@@ -591,7 +563,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
591
563
match place. layout . ty . kind ( ) {
592
564
& ty:: Ref ( _, pointee, mutability) => {
593
565
let new_perm =
594
- NewPermission :: from_ref_ty ( pointee, mutability, self . kind , self . ecx ) ;
566
+ NewPermission :: new ( pointee, Some ( mutability) , self . kind , self . ecx ) ;
595
567
self . retag_ptr_inplace ( place, new_perm) ?;
596
568
}
597
569
ty:: RawPtr ( _, _) => {
@@ -643,14 +615,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
643
615
// never be ReservedIM, the value of the `ty_is_freeze`
644
616
// argument doesn't matter
645
617
// (`ty_is_freeze || true` in `new_reserved` will always be `true`).
646
- freeze_perm : Permission :: new_reserved (
647
- /* ty_is_freeze */ true , /* protected */ true ,
648
- ) ,
618
+ freeze_perm : Permission :: new_reserved_frz ( ) ,
649
619
freeze_access : true ,
650
- nonfreeze_perm : Permission :: new_reserved (
651
- /* ty_is_freeze */ false , /* protected */ true ,
652
- ) ,
620
+ nonfreeze_perm : Permission :: new_reserved_frz ( ) ,
653
621
nonfreeze_access : true ,
622
+ outside_perm : Permission :: new_reserved_frz ( ) ,
654
623
protector : Some ( ProtectorKind :: StrongProtector ) ,
655
624
} ;
656
625
this. tb_retag_place ( place, new_perm)
0 commit comments