@@ -125,81 +125,64 @@ pub struct NewPermission {
125125 /// Whether a read access should be performed on the non-frozen
126126 /// part on a retag.
127127 nonfreeze_access : bool ,
128+ /// Permission for memory outside the range.
129+ outside_perm : Permission ,
128130 /// Whether this pointer is part of the arguments of a function call.
129131 /// `protector` is `Some(_)` for all pointers marked `noalias`.
130132 protector : Option < ProtectorKind > ,
131133}
132134
133135impl < ' 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 (
136140 pointee : Ty < ' tcx > ,
137- mutability : Mutability ,
138- kind : RetagKind ,
141+ ref_mutability : Option < Mutability > ,
142+ retag_kind : RetagKind ,
139143 cx : & crate :: MiriInterpCx < ' tcx > ,
140144 ) -> Option < Self > {
141145 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 ;
178148
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+ } ) ,
203186 } )
204187 }
205188}
@@ -313,15 +296,11 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
313296
314297 let span = this. machine . current_span ( ) ;
315298
316- // Store initial permissions and their corresponding range .
299+ // Store initial permissions for the "inside" part .
317300 let mut perms_map: DedupRangeMap < LocationState > = DedupRangeMap :: new (
318301 ptr_size,
319302 LocationState :: new_accessed ( Permission :: new_disabled ( ) , IdempotentForeignAccess :: None ) , // this will be overwritten
320303 ) ;
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 ;
325304
326305 // When adding a new node, the SIFA of its parents needs to be updated, potentially across
327306 // 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> {
350329 . get_tree_borrows_params ( )
351330 . precise_interior_mut ;
352331
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 {
357334 let ty_is_freeze = place. layout . ty . is_freeze ( * this. tcx , this. typing_env ( ) ) ;
358335 let ( perm, access) = if ty_is_freeze {
359336 ( new_perm. freeze_perm , new_perm. freeze_access )
360337 } else {
338+ // Just pretend the entire thing is an `UnsafeCell`.
361339 ( new_perm. nonfreeze_perm , new_perm. nonfreeze_access )
362340 } ;
363341 let sifa = perm. strongest_idempotent_foreign_access ( protected) ;
@@ -370,12 +348,8 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
370348 for ( _loc_range, loc) in perms_map. iter_mut_all ( ) {
371349 * loc = new_loc;
372350 }
373-
374- perm
375351 } else {
376352 this. visit_freeze_sensitive ( place, ptr_size, |range, frozen| {
377- has_unsafe_cell = has_unsafe_cell || !frozen;
378-
379353 // We are only ever `Frozen` inside the frozen bits.
380354 let ( perm, access) = if frozen {
381355 ( new_perm. freeze_perm , new_perm. freeze_access )
@@ -401,9 +375,6 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
401375
402376 interp_ok ( ( ) )
403377 } ) ?;
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 }
407378 } ;
408379
409380 let alloc_extra = this. get_alloc_extra ( alloc_id) ?;
@@ -447,7 +418,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
447418 orig_tag,
448419 new_tag,
449420 perms_map,
450- default_perm ,
421+ new_perm . outside_perm ,
451422 protected,
452423 span,
453424 ) ?;
@@ -514,7 +485,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
514485 let this = self . eval_context_mut ( ) ;
515486 let new_perm = match val. layout . ty . kind ( ) {
516487 & ty:: Ref ( _, pointee, mutability) =>
517- NewPermission :: from_ref_ty ( pointee, mutability, kind, this) ,
488+ NewPermission :: new ( pointee, Some ( mutability) , kind, this) ,
518489 _ => None ,
519490 } ;
520491 if let Some ( new_perm) = new_perm {
@@ -571,8 +542,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
571542 fn visit_box ( & mut self , box_ty : Ty < ' tcx > , place : & PlaceTy < ' tcx > ) -> InterpResult < ' tcx > {
572543 // Only boxes for the global allocator get any special treatment.
573544 if box_ty. is_box_global ( * self . ecx . tcx ) {
545+ let pointee = place. layout . ty . builtin_deref ( true ) . unwrap ( ) ;
574546 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 ) ;
576548 self . retag_ptr_inplace ( place, new_perm) ?;
577549 }
578550 interp_ok ( ( ) )
@@ -591,7 +563,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
591563 match place. layout . ty . kind ( ) {
592564 & ty:: Ref ( _, pointee, mutability) => {
593565 let new_perm =
594- NewPermission :: from_ref_ty ( pointee, mutability, self . kind , self . ecx ) ;
566+ NewPermission :: new ( pointee, Some ( mutability) , self . kind , self . ecx ) ;
595567 self . retag_ptr_inplace ( place, new_perm) ?;
596568 }
597569 ty:: RawPtr ( _, _) => {
@@ -643,14 +615,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
643615 // never be ReservedIM, the value of the `ty_is_freeze`
644616 // argument doesn't matter
645617 // (`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 ( ) ,
649619 freeze_access : true ,
650- nonfreeze_perm : Permission :: new_reserved (
651- /* ty_is_freeze */ false , /* protected */ true ,
652- ) ,
620+ nonfreeze_perm : Permission :: new_reserved_frz ( ) ,
653621 nonfreeze_access : true ,
622+ outside_perm : Permission :: new_reserved_frz ( ) ,
654623 protector : Some ( ProtectorKind :: StrongProtector ) ,
655624 } ;
656625 this. tb_retag_place ( place, new_perm)
0 commit comments