drop perform_read_access (always read) in favor of zero_size

This commit is contained in:
Neven Villani 2023-06-19 12:05:30 +02:00
parent 878c6ae390
commit 65d60f9f11
No known key found for this signature in database
GPG key ID: 00E765FA7F4F2EDE

View file

@ -99,9 +99,9 @@ impl<'tcx> Tree {
/// Policy for a new borrow.
#[derive(Debug, Clone, Copy)]
struct NewPermission {
/// Whether this borrow requires a read access on its parent.
/// `perform_read_access` is `true` for all pointers marked `dereferenceable`.
perform_read_access: bool,
/// Optionally ignore the actual size to do a zero-size reborrow.
/// If this is set then `dereferenceable` is not enforced.
zero_size: bool,
/// Which permission should the pointer start with.
initial_state: Permission,
/// Whether this pointer is part of the arguments of a function call.
@ -128,20 +128,19 @@ impl<'tcx> NewPermission {
// `&`s, which are excluded above.
_ => return None,
};
// This field happens to be redundant since right now we always do a read,
// but it could be useful in the future.
let perform_read_access = true;
let protector = (kind == RetagKind::FnEntry).then_some(ProtectorKind::StrongProtector);
Some(Self { perform_read_access, initial_state, protector })
Some(Self { zero_size: false, initial_state, protector })
}
// Boxes are not handled by `from_ref_ty`, they need special behavior
// implemented here.
fn from_box_ty(
/// Compute permission for `Box`-like type (`Box` always, and also `Unique` if enabled).
/// These pointers allow deallocation so need a different kind of protector not handled
/// by `from_ref_ty`.
fn from_unique_ty(
ty: Ty<'tcx>,
kind: RetagKind,
cx: &crate::MiriInterpCx<'_, 'tcx>,
zero_size: bool,
) -> Option<Self> {
let pointee = ty.builtin_deref(true).unwrap().ty;
pointee.is_unpin(*cx.tcx, cx.param_env()).then_some(()).map(|()| {
@ -149,7 +148,7 @@ impl<'tcx> NewPermission {
// because it is valid to deallocate it within the function.
let ty_is_freeze = ty.is_freeze(*cx.tcx, cx.param_env());
Self {
perform_read_access: true,
zero_size,
initial_state: Permission::new_unique_2phase(ty_is_freeze),
protector: (kind == RetagKind::FnEntry).then_some(ProtectorKind::WeakProtector),
}
@ -201,6 +200,7 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
Ok(())
};
trace!("Reborrow of size {:?}", ptr_size);
let (alloc_id, base_offset, parent_prov) = if ptr_size > Size::ZERO {
this.ptr_get_alloc_id(place.ptr)?
} else {
@ -276,8 +276,8 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
let range = alloc_range(base_offset, ptr_size);
let mut tree_borrows = alloc_extra.borrow_tracker_tb().borrow_mut();
if new_perm.perform_read_access {
// Count this reborrow as a read access
// All reborrows incur a (possibly zero-sized) read access to the parent
{
let global = &this.machine.borrow_tracker.as_ref().unwrap();
let span = this.machine.current_span();
tree_borrows.perform_access(
@ -308,12 +308,19 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
// We want a place for where the ptr *points to*, so we get one.
let place = this.ref_to_mplace(val)?;
// Get a lower bound of the size of this place.
// (When `extern type` are involved, use the size of the known prefix.)
let size = this
.size_and_align_of_mplace(&place)?
.map(|(size, _)| size)
.unwrap_or(place.layout.size);
// Determine the size of the reborrow.
// For most types this is the entire size of the place, however
// - when `extern type` is involved we use the size of the known prefix,
// - if the pointer is not reborrowed (raw pointer) or if `zero_size` is set
// then we override the size to do a zero-length reborrow.
let reborrow_size = match new_perm {
Some(NewPermission { zero_size: false, .. }) =>
this.size_and_align_of_mplace(&place)?
.map(|(size, _)| size)
.unwrap_or(place.layout.size),
_ => Size::from_bytes(0),
};
trace!("Creating new permission: {:?} with size {:?}", new_perm, reborrow_size);
// This new tag is not guaranteed to actually be used.
//
@ -324,7 +331,7 @@ trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriInterpCxExt<'
let new_tag = this.machine.borrow_tracker.as_mut().unwrap().get_mut().new_ptr();
// Compute the actual reborrow.
let reborrowed = this.tb_reborrow(&place, size, new_perm, new_tag)?;
let reborrowed = this.tb_reborrow(&place, reborrow_size, new_perm, new_tag)?;
// Adjust pointer.
let new_place = place.map_provenance(|p| {
@ -359,10 +366,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
val: &ImmTy<'tcx, Provenance>,
) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> {
let this = self.eval_context_mut();
let new_perm = if let &ty::Ref(_, pointee, mutability) = val.layout.ty.kind() {
NewPermission::from_ref_ty(pointee, mutability, kind, this)
} else {
None
let new_perm = match val.layout.ty.kind() {
&ty::Ref(_, pointee, mutability) =>
NewPermission::from_ref_ty(pointee, mutability, kind, this),
_ => None,
};
this.tb_retag_reference(val, new_perm)
}
@ -408,7 +415,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
}
fn visit_box(&mut self, place: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> {
let new_perm = NewPermission::from_box_ty(place.layout.ty, self.kind, self.ecx);
let new_perm = NewPermission::from_unique_ty(
place.layout.ty,
self.kind,
self.ecx,
/* zero_size */ false,
);
self.retag_ptr_inplace(place, new_perm)
}
@ -486,7 +498,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
// FIXME: do we truly want a 2phase borrow here?
let new_perm = Some(NewPermission {
initial_state: Permission::new_unique_2phase(/*freeze*/ false),
perform_read_access: true,
zero_size: false,
protector: Some(ProtectorKind::StrongProtector),
});
let val = this.tb_retag_reference(&val, new_perm)?;