@@ -99,9 +99,9 @@ impl<'tcx> Tree {
9999/// Policy for a new borrow.
100100#[ derive( Debug , Clone , Copy ) ]
101101struct 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 ,
105105 /// Which permission should the pointer start with.
106106 initial_state : Permission ,
107107 /// Whether this pointer is part of the arguments of a function call.
@@ -128,28 +128,27 @@ impl<'tcx> NewPermission {
128128 // `&`s, which are excluded above.
129129 _ => return None ,
130130 } ;
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 ;
134131
135132 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 } )
137134 }
138135
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 (
142140 ty : Ty < ' tcx > ,
143141 kind : RetagKind ,
144142 cx : & crate :: MiriInterpCx < ' _ , ' tcx > ,
143+ zero_size : bool ,
145144 ) -> Option < Self > {
146145 let pointee = ty. builtin_deref ( true ) . unwrap ( ) . ty ;
147146 pointee. is_unpin ( * cx. tcx , cx. param_env ( ) ) . then_some ( ( ) ) . map ( |( ) | {
148147 // Regular `Unpin` box, give it `noalias` but only a weak protector
149148 // because it is valid to deallocate it within the function.
150149 let ty_is_freeze = ty. is_freeze ( * cx. tcx , cx. param_env ( ) ) ;
151150 Self {
152- perform_read_access : true ,
151+ zero_size ,
153152 initial_state : Permission :: new_unique_2phase ( ty_is_freeze) ,
154153 protector : ( kind == RetagKind :: FnEntry ) . then_some ( ProtectorKind :: WeakProtector ) ,
155154 }
@@ -201,6 +200,7 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
201200 Ok ( ( ) )
202201 } ;
203202
203+ trace ! ( "Reborrow of size {:?}" , ptr_size) ;
204204 let ( alloc_id, base_offset, parent_prov) = if ptr_size > Size :: ZERO {
205205 this. ptr_get_alloc_id ( place. ptr ) ?
206206 } else {
@@ -276,8 +276,8 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
276276 let range = alloc_range ( base_offset, ptr_size) ;
277277 let mut tree_borrows = alloc_extra. borrow_tracker_tb ( ) . borrow_mut ( ) ;
278278
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+ {
281281 let global = & this. machine . borrow_tracker . as_ref ( ) . unwrap ( ) ;
282282 let span = this. machine . current_span ( ) ;
283283 tree_borrows. perform_access (
@@ -308,12 +308,19 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
308308 // We want a place for where the ptr *points to*, so we get one.
309309 let place = this. ref_to_mplace ( val) ?;
310310
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) ;
317324
318325 // This new tag is not guaranteed to actually be used.
319326 //
@@ -324,7 +331,7 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
324331 let new_tag = this. machine . borrow_tracker . as_mut ( ) . unwrap ( ) . get_mut ( ) . new_ptr ( ) ;
325332
326333 // 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) ?;
328335
329336 // Adjust pointer.
330337 let new_place = place. map_provenance ( |p| {
@@ -359,10 +366,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
359366 val : & ImmTy < ' tcx , Provenance > ,
360367 ) -> InterpResult < ' tcx , ImmTy < ' tcx , Provenance > > {
361368 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 ,
366373 } ;
367374 this. tb_retag_reference ( val, new_perm)
368375 }
@@ -408,7 +415,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
408415 }
409416
410417 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+ ) ;
412424 self . retag_ptr_inplace ( place, new_perm)
413425 }
414426
@@ -486,7 +498,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
486498 // FIXME: do we truly want a 2phase borrow here?
487499 let new_perm = Some ( NewPermission {
488500 initial_state : Permission :: new_unique_2phase ( /*freeze*/ false ) ,
489- perform_read_access : true ,
501+ zero_size : false ,
490502 protector : Some ( ProtectorKind :: StrongProtector ) ,
491503 } ) ;
492504 let val = this. tb_retag_reference ( & val, new_perm) ?;
0 commit comments