@@ -117,7 +117,7 @@ impl<'tcx> NewPermission {
117117 let ty_is_freeze = pointee. is_freeze ( * cx. tcx , cx. param_env ( ) ) ;
118118 let ty_is_unpin = pointee. is_unpin ( * cx. tcx , cx. param_env ( ) ) ;
119119 let initial_state = match mutability {
120- Mutability :: Mut if ty_is_unpin => Permission :: new_unique_2phase ( ty_is_freeze) ,
120+ Mutability :: Mut if ty_is_unpin => Permission :: new_reserved ( ty_is_freeze) ,
121121 Mutability :: Not if ty_is_freeze => Permission :: new_frozen ( ) ,
122122 // Raw pointers never enter this function so they are not handled.
123123 // However raw pointers are not the only pointers that take the parent
@@ -146,7 +146,7 @@ impl<'tcx> NewPermission {
146146 let ty_is_freeze = ty. is_freeze ( * cx. tcx , cx. param_env ( ) ) ;
147147 Self {
148148 zero_size,
149- initial_state : Permission :: new_unique_2phase ( ty_is_freeze) ,
149+ initial_state : Permission :: new_reserved ( ty_is_freeze) ,
150150 protector : ( kind == RetagKind :: FnEntry ) . then_some ( ProtectorKind :: WeakProtector ) ,
151151 }
152152 } )
@@ -161,22 +161,14 @@ impl<'mir: 'ecx, 'tcx: 'mir, 'ecx> EvalContextPrivExt<'mir, 'tcx, 'ecx>
161161{
162162}
163163trait EvalContextPrivExt < ' mir : ' ecx , ' tcx : ' mir , ' ecx > : crate :: MiriInterpCxExt < ' mir , ' tcx > {
164- /// Returns the `AllocId` the reborrow was done in, if there is some actual
165- /// memory associated with this pointer. Returns `None` if there is no actual
166- /// memory allocated. Also checks that the reborrow of size `ptr_size` is
167- /// within bounds of the allocation.
168- ///
169- /// Also returns the tag that the pointer should get, which is essentially
170- /// `if new_perm.is_some() { new_tag } else { parent_tag }` along with
171- /// some logging (always) and fake reads (if `new_perm` is
172- /// `Some(NewPermission { perform_read_access: true }`).
164+ /// Returns the provenance that should be used henceforth.
173165 fn tb_reborrow (
174166 & mut self ,
175167 place : & MPlaceTy < ' tcx , Provenance > , // parent tag extracted from here
176168 ptr_size : Size ,
177169 new_perm : NewPermission ,
178170 new_tag : BorTag ,
179- ) -> InterpResult < ' tcx , Option < ( AllocId , BorTag ) > > {
171+ ) -> InterpResult < ' tcx , Option < Provenance > > {
180172 let this = self . eval_context_mut ( ) ;
181173 // Ensure we bail out if the pointer goes out-of-bounds (see miri#1050).
182174 this. check_ptr_access_align (
@@ -222,13 +214,14 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
222214 place. layout. ty,
223215 ) ;
224216 log_creation ( this, None ) ?;
225- return Ok ( None ) ;
217+ // Keep original provenance.
218+ return Ok ( place. ptr . provenance ) ;
226219 }
227220 } ;
228221 log_creation ( this, Some ( ( alloc_id, base_offset, parent_prov) ) ) ?;
229222
230223 let orig_tag = match parent_prov {
231- ProvenanceExtra :: Wildcard => return Ok ( None ) , // TODO: handle wildcard pointers
224+ ProvenanceExtra :: Wildcard => return Ok ( place . ptr . provenance ) , // TODO: handle wildcard pointers
232225 ProvenanceExtra :: Concrete ( tag) => tag,
233226 } ;
234227
@@ -255,31 +248,54 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
255248 . insert ( new_tag, protect) ;
256249 }
257250
251+ let alloc_kind = this. get_alloc_info ( alloc_id) . 2 ;
252+ if !matches ! ( alloc_kind, AllocKind :: LiveData ) {
253+ assert_eq ! ( ptr_size, Size :: ZERO ) ; // we did the deref check above, size has to be 0 here
254+ // There's not actually any bytes here where accesses could even be tracked.
255+ // Just produce the new provenance, nothing else to do.
256+ return Ok ( Some ( Provenance :: Concrete { alloc_id, tag : new_tag } ) ) ;
257+ }
258+
258259 let span = this. machine . current_span ( ) ;
259260 let alloc_extra = this. get_alloc_extra ( alloc_id) ?;
260261 let range = alloc_range ( base_offset, ptr_size) ;
261262 let mut tree_borrows = alloc_extra. borrow_tracker_tb ( ) . borrow_mut ( ) ;
262263
263264 // All reborrows incur a (possibly zero-sized) read access to the parent
264- {
265- let global = & this. machine . borrow_tracker . as_ref ( ) . unwrap ( ) ;
266- let span = this. machine . current_span ( ) ;
267- tree_borrows. perform_access (
268- AccessKind :: Read ,
269- orig_tag,
270- range,
271- global,
272- span,
273- diagnostics:: AccessCause :: Reborrow ,
274- ) ?;
265+ tree_borrows. perform_access (
266+ AccessKind :: Read ,
267+ orig_tag,
268+ range,
269+ this. machine . borrow_tracker . as_ref ( ) . unwrap ( ) ,
270+ this. machine . current_span ( ) ,
271+ diagnostics:: AccessCause :: Reborrow ,
272+ ) ?;
273+ // Record the parent-child pair in the tree.
274+ tree_borrows. new_child ( orig_tag, new_tag, new_perm. initial_state , range, span) ?;
275+ drop ( tree_borrows) ;
276+
277+ // Also inform the data race model (but only if any bytes are actually affected).
278+ if range. size . bytes ( ) > 0 {
275279 if let Some ( data_race) = alloc_extra. data_race . as_ref ( ) {
276- data_race. read ( alloc_id, range, & this. machine ) ?;
280+ // We sometimes need to make it a write, since not all retags commute with reads!
281+ // FIXME: Is that truly the semantics we want? Some optimizations are likely to be
282+ // very unhappy without this. We'd tsill ge some UB just by picking a suitable
283+ // interleaving, but wether UB happens can depend on whether a write occurs in the
284+ // future...
285+ let is_write = new_perm. initial_state . is_active ( )
286+ || ( new_perm. initial_state . is_resrved ( ) && new_perm. protector . is_some ( ) ) ;
287+ if is_write {
288+ // Need to get mutable access to alloc_extra.
289+ // (Cannot always do this as we can do read-only reborrowing on read-only allocations.)
290+ let ( alloc_extra, machine) = this. get_alloc_extra_mut ( alloc_id) ?;
291+ alloc_extra. data_race . as_mut ( ) . unwrap ( ) . write ( alloc_id, range, machine) ?;
292+ } else {
293+ data_race. read ( alloc_id, range, & this. machine ) ?;
294+ }
277295 }
278296 }
279297
280- // Record the parent-child pair in the tree.
281- tree_borrows. new_child ( orig_tag, new_tag, new_perm. initial_state , range, span) ?;
282- Ok ( Some ( ( alloc_id, new_tag) ) )
298+ Ok ( Some ( Provenance :: Concrete { alloc_id, tag : new_tag } ) )
283299 }
284300
285301 /// Retags an individual pointer, returning the retagged version.
@@ -315,25 +331,10 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
315331 let new_tag = this. machine . borrow_tracker . as_mut ( ) . unwrap ( ) . get_mut ( ) . new_ptr ( ) ;
316332
317333 // Compute the actual reborrow.
318- let reborrowed = this. tb_reborrow ( & place, reborrow_size, new_perm, new_tag) ?;
334+ let new_prov = this. tb_reborrow ( & place, reborrow_size, new_perm, new_tag) ?;
319335
320336 // Adjust pointer.
321- let new_place = place. map_provenance ( |p| {
322- p. map ( |prov| {
323- match reborrowed {
324- Some ( ( alloc_id, actual_tag) ) => {
325- // If `reborrow` could figure out the AllocId of this ptr, hard-code it into the new one.
326- // Even if we started out with a wildcard, this newly retagged pointer is tied to that allocation.
327- Provenance :: Concrete { alloc_id, tag : actual_tag }
328- }
329- None => {
330- // Looks like this has to stay a wildcard pointer.
331- assert ! ( matches!( prov, Provenance :: Wildcard ) ) ;
332- Provenance :: Wildcard
333- }
334- }
335- } )
336- } ) ;
337+ let new_place = place. map_provenance ( |_| new_prov) ;
337338
338339 // Return new pointer.
339340 Ok ( ImmTy :: from_immediate ( new_place. to_ref ( this) , val. layout ) )
0 commit comments