@@ -117,7 +117,7 @@ impl<'tcx> NewPermission {
117
117
let ty_is_freeze = pointee. is_freeze ( * cx. tcx , cx. param_env ( ) ) ;
118
118
let ty_is_unpin = pointee. is_unpin ( * cx. tcx , cx. param_env ( ) ) ;
119
119
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) ,
121
121
Mutability :: Not if ty_is_freeze => Permission :: new_frozen ( ) ,
122
122
// Raw pointers never enter this function so they are not handled.
123
123
// However raw pointers are not the only pointers that take the parent
@@ -146,7 +146,7 @@ impl<'tcx> NewPermission {
146
146
let ty_is_freeze = ty. is_freeze ( * cx. tcx , cx. param_env ( ) ) ;
147
147
Self {
148
148
zero_size,
149
- initial_state : Permission :: new_unique_2phase ( ty_is_freeze) ,
149
+ initial_state : Permission :: new_reserved ( ty_is_freeze) ,
150
150
protector : ( kind == RetagKind :: FnEntry ) . then_some ( ProtectorKind :: WeakProtector ) ,
151
151
}
152
152
} )
@@ -161,22 +161,14 @@ impl<'mir: 'ecx, 'tcx: 'mir, 'ecx> EvalContextPrivExt<'mir, 'tcx, 'ecx>
161
161
{
162
162
}
163
163
trait 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.
173
165
fn tb_reborrow (
174
166
& mut self ,
175
167
place : & MPlaceTy < ' tcx , Provenance > , // parent tag extracted from here
176
168
ptr_size : Size ,
177
169
new_perm : NewPermission ,
178
170
new_tag : BorTag ,
179
- ) -> InterpResult < ' tcx , Option < ( AllocId , BorTag ) > > {
171
+ ) -> InterpResult < ' tcx , Option < Provenance > > {
180
172
let this = self . eval_context_mut ( ) ;
181
173
// Ensure we bail out if the pointer goes out-of-bounds (see miri#1050).
182
174
this. check_ptr_access_align (
@@ -222,13 +214,14 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
222
214
place. layout. ty,
223
215
) ;
224
216
log_creation ( this, None ) ?;
225
- return Ok ( None ) ;
217
+ // Keep original provenance.
218
+ return Ok ( place. ptr . provenance ) ;
226
219
}
227
220
} ;
228
221
log_creation ( this, Some ( ( alloc_id, base_offset, parent_prov) ) ) ?;
229
222
230
223
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
232
225
ProvenanceExtra :: Concrete ( tag) => tag,
233
226
} ;
234
227
@@ -255,31 +248,54 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
255
248
. insert ( new_tag, protect) ;
256
249
}
257
250
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
+
258
259
let span = this. machine . current_span ( ) ;
259
260
let alloc_extra = this. get_alloc_extra ( alloc_id) ?;
260
261
let range = alloc_range ( base_offset, ptr_size) ;
261
262
let mut tree_borrows = alloc_extra. borrow_tracker_tb ( ) . borrow_mut ( ) ;
262
263
263
264
// 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 {
275
279
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
+ }
277
295
}
278
296
}
279
297
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 } ) )
283
299
}
284
300
285
301
/// Retags an individual pointer, returning the retagged version.
@@ -315,25 +331,10 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
315
331
let new_tag = this. machine . borrow_tracker . as_mut ( ) . unwrap ( ) . get_mut ( ) . new_ptr ( ) ;
316
332
317
333
// 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) ?;
319
335
320
336
// 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) ;
337
338
338
339
// Return new pointer.
339
340
Ok ( ImmTy :: from_immediate ( new_place. to_ref ( this) , val. layout ) )
0 commit comments