Skip to content

Commit df1a7c0

Browse files
committed
drop perform_read_access (always read) in favor of zero_size
1 parent dd100bf commit df1a7c0

File tree

1 file changed

+38
-26
lines changed
  • src/borrow_tracker/tree_borrows

1 file changed

+38
-26
lines changed

src/borrow_tracker/tree_borrows/mod.rs

Lines changed: 38 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,9 @@ impl<'tcx> Tree {
9999
/// Policy for a new borrow.
100100
#[derive(Debug, Clone, Copy)]
101101
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,
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

Comments
 (0)