@@ -99,9 +99,9 @@ impl<'tcx> Tree {
99
99
/// Policy for a new borrow.
100
100
#[ derive( Debug , Clone , Copy ) ]
101
101
struct NewPermission {
102
- /// Whether this borrow requires a read access on its parent .
103
- /// `perform_read_access` is `true` for all pointers marked `dereferenceable`.
104
- perform_read_access : bool ,
102
+ /// Optionally ignore the actual size to do a zero-size reborrow .
103
+ /// If this is set then `dereferenceable` is not enforced .
104
+ zero_size : bool ,
105
105
/// Which permission should the pointer start with.
106
106
initial_state : Permission ,
107
107
/// Whether this pointer is part of the arguments of a function call.
@@ -128,28 +128,27 @@ impl<'tcx> NewPermission {
128
128
// `&`s, which are excluded above.
129
129
_ => return None ,
130
130
} ;
131
- // This field happens to be redundant since right now we always do a read,
132
- // but it could be useful in the future.
133
- let perform_read_access = true ;
134
131
135
132
let protector = ( kind == RetagKind :: FnEntry ) . then_some ( ProtectorKind :: StrongProtector ) ;
136
- Some ( Self { perform_read_access , initial_state, protector } )
133
+ Some ( Self { zero_size : false , initial_state, protector } )
137
134
}
138
135
139
- // Boxes are not handled by `from_ref_ty`, they need special behavior
140
- // implemented here.
141
- fn from_box_ty (
136
+ /// Compute permission for `Box`-like type (`Box` always, and also `Unique` if enabled).
137
+ /// These pointers allow deallocation so need a different kind of protector not handled
138
+ /// by `from_ref_ty`.
139
+ fn from_unique_ty (
142
140
ty : Ty < ' tcx > ,
143
141
kind : RetagKind ,
144
142
cx : & crate :: MiriInterpCx < ' _ , ' tcx > ,
143
+ zero_size : bool ,
145
144
) -> Option < Self > {
146
145
let pointee = ty. builtin_deref ( true ) . unwrap ( ) . ty ;
147
146
pointee. is_unpin ( * cx. tcx , cx. param_env ( ) ) . then_some ( ( ) ) . map ( |( ) | {
148
147
// Regular `Unpin` box, give it `noalias` but only a weak protector
149
148
// because it is valid to deallocate it within the function.
150
149
let ty_is_freeze = ty. is_freeze ( * cx. tcx , cx. param_env ( ) ) ;
151
150
Self {
152
- perform_read_access : true ,
151
+ zero_size ,
153
152
initial_state : Permission :: new_unique_2phase ( ty_is_freeze) ,
154
153
protector : ( kind == RetagKind :: FnEntry ) . then_some ( ProtectorKind :: WeakProtector ) ,
155
154
}
@@ -201,6 +200,7 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
201
200
Ok ( ( ) )
202
201
} ;
203
202
203
+ trace ! ( "Reborrow of size {:?}" , ptr_size) ;
204
204
let ( alloc_id, base_offset, parent_prov) = if ptr_size > Size :: ZERO {
205
205
this. ptr_get_alloc_id ( place. ptr ) ?
206
206
} else {
@@ -276,8 +276,8 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
276
276
let range = alloc_range ( base_offset, ptr_size) ;
277
277
let mut tree_borrows = alloc_extra. borrow_tracker_tb ( ) . borrow_mut ( ) ;
278
278
279
- if new_perm . perform_read_access {
280
- // Count this reborrow as a read access
279
+ // All reborrows incur a (possibly zero-sized) read access to the parent
280
+ {
281
281
let global = & this. machine . borrow_tracker . as_ref ( ) . unwrap ( ) ;
282
282
let span = this. machine . current_span ( ) ;
283
283
tree_borrows. perform_access (
@@ -308,12 +308,19 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
308
308
// We want a place for where the ptr *points to*, so we get one.
309
309
let place = this. ref_to_mplace ( val) ?;
310
310
311
- // Get a lower bound of the size of this place.
312
- // (When `extern type` are involved, use the size of the known prefix.)
313
- let size = this
314
- . size_and_align_of_mplace ( & place) ?
315
- . map ( |( size, _) | size)
316
- . unwrap_or ( place. layout . size ) ;
311
+ // Determine the size of the reborrow.
312
+ // For most types this is the entire size of the place, however
313
+ // - when `extern type` is involved we use the size of the known prefix,
314
+ // - if the pointer is not reborrowed (raw pointer) or if `zero_size` is set
315
+ // then we override the size to do a zero-length reborrow.
316
+ let reborrow_size = match new_perm {
317
+ Some ( NewPermission { zero_size : false , .. } ) =>
318
+ this. size_and_align_of_mplace ( & place) ?
319
+ . map ( |( size, _) | size)
320
+ . unwrap_or ( place. layout . size ) ,
321
+ _ => Size :: from_bytes ( 0 ) ,
322
+ } ;
323
+ trace ! ( "Creating new permission: {:?} with size {:?}" , new_perm, reborrow_size) ;
317
324
318
325
// This new tag is not guaranteed to actually be used.
319
326
//
@@ -324,7 +331,7 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
324
331
let new_tag = this. machine . borrow_tracker . as_mut ( ) . unwrap ( ) . get_mut ( ) . new_ptr ( ) ;
325
332
326
333
// Compute the actual reborrow.
327
- let reborrowed = this. tb_reborrow ( & place, size , new_perm, new_tag) ?;
334
+ let reborrowed = this. tb_reborrow ( & place, reborrow_size , new_perm, new_tag) ?;
328
335
329
336
// Adjust pointer.
330
337
let new_place = place. map_provenance ( |p| {
@@ -359,10 +366,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
359
366
val : & ImmTy < ' tcx , Provenance > ,
360
367
) -> InterpResult < ' tcx , ImmTy < ' tcx , Provenance > > {
361
368
let this = self . eval_context_mut ( ) ;
362
- let new_perm = if let & ty :: Ref ( _ , pointee , mutability ) = val. layout . ty . kind ( ) {
363
- NewPermission :: from_ref_ty ( pointee , mutability , kind , this )
364
- } else {
365
- None
369
+ let new_perm = match val. layout . ty . kind ( ) {
370
+ & ty :: Ref ( _ , pointee , mutability ) =>
371
+ NewPermission :: from_ref_ty ( pointee , mutability , kind , this ) ,
372
+ _ => None ,
366
373
} ;
367
374
this. tb_retag_reference ( val, new_perm)
368
375
}
@@ -408,7 +415,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
408
415
}
409
416
410
417
fn visit_box ( & mut self , place : & PlaceTy < ' tcx , Provenance > ) -> InterpResult < ' tcx > {
411
- let new_perm = NewPermission :: from_box_ty ( place. layout . ty , self . kind , self . ecx ) ;
418
+ let new_perm = NewPermission :: from_unique_ty (
419
+ place. layout . ty ,
420
+ self . kind ,
421
+ self . ecx ,
422
+ /* zero_size */ false ,
423
+ ) ;
412
424
self . retag_ptr_inplace ( place, new_perm)
413
425
}
414
426
@@ -486,7 +498,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
486
498
// FIXME: do we truly want a 2phase borrow here?
487
499
let new_perm = Some ( NewPermission {
488
500
initial_state : Permission :: new_unique_2phase ( /*freeze*/ false ) ,
489
- perform_read_access : true ,
501
+ zero_size : false ,
490
502
protector : Some ( ProtectorKind :: StrongProtector ) ,
491
503
} ) ;
492
504
let val = this. tb_retag_reference ( & val, new_perm) ?;
0 commit comments