Skip to content

Commit bbe05dc

Browse files
committed
Tree::new_child: remove SIFA precondition and sync terminology
1 parent 1c31602 commit bbe05dc

File tree

4 files changed

+34
-70
lines changed

4 files changed

+34
-70
lines changed

src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -504,7 +504,7 @@ impl DisplayFmt {
504504
if let Some(perm) = perm {
505505
format!(
506506
"{ac}{st}",
507-
ac = if perm.is_accessed() { self.accessed.yes } else { self.accessed.no },
507+
ac = if perm.accessed() { self.accessed.yes } else { self.accessed.no },
508508
st = perm.permission().short_name(),
509509
)
510510
} else {

src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs

Lines changed: 5 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -294,24 +294,6 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
294294
return interp_ok(Some(Provenance::Concrete { alloc_id, tag: new_tag }));
295295
}
296296

297-
let span = this.machine.current_span();
298-
299-
// When adding a new node, the SIFA of its parents needs to be updated, potentially across
300-
// the entire memory range. For the parts that are being accessed below, the access itself
301-
// trivially takes care of that. However, we have to do some more work to also deal with the
302-
// parts that are not being accessed. Specifically what we do is that we call
303-
// `update_last_accessed_after_retag` on the SIFA of the permission set for the part of
304-
// memory outside `perm_map` -- so that part is definitely taken care of. The remaining
305-
// concern is the part of memory that is in the range of `perms_map`, but not accessed
306-
// below. There we have two cases:
307-
// * If the type is `!Freeze`, then the non-accessed part uses `nonfreeze_perm`, so the
308-
// `nonfreeze_perm` initialized parts are also fine. We enforce the `freeze_perm` parts to
309-
// be accessed via the assert below, and thus everything is taken care of.
310-
// * If the type is `Freeze`, then `freeze_perm` is used everywhere (both inside and outside
311-
// the initial range), and we update everything to have the `freeze_perm`'s SIFA, so there
312-
// are no issues. (And this assert below is not actually needed in this case).
313-
assert!(new_perm.freeze_access);
314-
315297
let protected = new_perm.protector.is_some();
316298
let precise_interior_mut = this
317299
.machine
@@ -337,7 +319,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
337319
LocationState::new_non_accessed(perm, sifa)
338320
}
339321
};
340-
let perms_map = if !precise_interior_mut {
322+
let inside_perms = if !precise_interior_mut {
341323
// For `!Freeze` types, just pretend the entire thing is an `UnsafeCell`.
342324
let ty_is_freeze = place.layout.ty.is_freeze(*this.tcx, this.typing_env());
343325
let state = loc_state(ty_is_freeze);
@@ -364,8 +346,8 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
364346
let alloc_extra = this.get_alloc_extra(alloc_id)?;
365347
let mut tree_borrows = alloc_extra.borrow_tracker_tb().borrow_mut();
366348

367-
for (perm_range, perm) in perms_map.iter_all() {
368-
if perm.is_accessed() {
349+
for (perm_range, perm) in inside_perms.iter_all() {
350+
if perm.accessed() {
369351
// Some reborrows incur a read access to the parent.
370352
// Adjust range to be relative to allocation start (rather than to `place`).
371353
let range_in_alloc = AllocRange {
@@ -401,10 +383,10 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
401383
base_offset,
402384
orig_tag,
403385
new_tag,
404-
perms_map,
386+
inside_perms,
405387
new_perm.outside_perm,
406388
protected,
407-
span,
389+
this.machine.current_span(),
408390
)?;
409391
drop(tree_borrows);
410392

src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs

Lines changed: 25 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
//! - idempotency properties asserted in `perms.rs` (for optimizations)
1212
1313
use std::ops::Range;
14-
use std::{fmt, mem};
14+
use std::{cmp, fmt, mem};
1515

1616
use rustc_abi::Size;
1717
use rustc_data_structures::fx::FxHashSet;
@@ -73,23 +73,10 @@ impl LocationState {
7373

7474
/// Check if the location has been accessed, i.e. if it has
7575
/// ever been accessed through a child pointer.
76-
pub fn is_accessed(&self) -> bool {
76+
pub fn accessed(&self) -> bool {
7777
self.accessed
7878
}
7979

80-
/// Check if the state can exist as the initial permission of a pointer.
81-
///
82-
/// Do not confuse with `is_accessed`, the two are almost orthogonal
83-
/// as apart from `Unique` which is not initial and must be accessed,
84-
/// any other permission can have an arbitrary combination of being
85-
/// initial/accessed.
86-
/// FIXME: when the corresponding `assert` in `tree_borrows/mod.rs` finally
87-
/// passes and can be uncommented, remove this `#[allow(dead_code)]`.
88-
#[cfg_attr(not(test), allow(dead_code))]
89-
pub fn is_initial(&self) -> bool {
90-
self.permission.is_initial()
91-
}
92-
9380
pub fn permission(&self) -> Permission {
9481
self.permission
9582
}
@@ -618,67 +605,62 @@ impl Tree {
618605
impl<'tcx> Tree {
619606
/// Insert a new tag in the tree.
620607
///
621-
/// `initial_perms` defines the initial permissions for the part of memory
622-
/// that is already considered "initialized" immediately. The ranges in this
623-
/// map are relative to `base_offset`.
624-
/// `default_perm` defines the initial permission for the rest of the allocation.
625-
///
626-
/// For all non-accessed locations in the RangeMap (those that haven't had an
627-
/// implicit read), their SIFA must be weaker than or as weak as the SIFA of
628-
/// `default_perm`.
608+
/// `inside_perm` defines the initial permissions for a block of memory starting at
609+
/// `base_offset`. These may nor may not be already marked as "accessed".
610+
/// `outside_perm` defines the initial permission for the rest of the allocation.
611+
/// These are definitely not "accessed".
629612
pub(super) fn new_child(
630613
&mut self,
631614
base_offset: Size,
632615
parent_tag: BorTag,
633616
new_tag: BorTag,
634-
initial_perms: DedupRangeMap<LocationState>,
635-
default_perm: Permission,
617+
inside_perms: DedupRangeMap<LocationState>,
618+
outside_perm: Permission,
636619
protected: bool,
637620
span: Span,
638621
) -> InterpResult<'tcx> {
639622
let idx = self.tag_mapping.insert(new_tag);
640623
let parent_idx = self.tag_mapping.get(&parent_tag).unwrap();
641-
assert!(default_perm.is_initial());
624+
assert!(outside_perm.is_initial());
642625

643626
let default_strongest_idempotent =
644-
default_perm.strongest_idempotent_foreign_access(protected);
627+
outside_perm.strongest_idempotent_foreign_access(protected);
645628
// Create the node
646629
self.nodes.insert(
647630
idx,
648631
Node {
649632
tag: new_tag,
650633
parent: Some(parent_idx),
651634
children: SmallVec::default(),
652-
default_initial_perm: default_perm,
635+
default_initial_perm: outside_perm,
653636
default_initial_idempotent_foreign_access: default_strongest_idempotent,
654-
debug_info: NodeDebugInfo::new(new_tag, default_perm, span),
637+
debug_info: NodeDebugInfo::new(new_tag, outside_perm, span),
655638
},
656639
);
657640
// Register new_tag as a child of parent_tag
658641
self.nodes.get_mut(parent_idx).unwrap().children.push(idx);
659642

643+
// We need to know the biggest SIFA for `update_last_accessed_after_retag` below.
644+
let mut max_sifa = default_strongest_idempotent;
660645
for (Range { start, end }, &perm) in
661-
initial_perms.iter(Size::from_bytes(0), initial_perms.size())
646+
inside_perms.iter(Size::from_bytes(0), inside_perms.size())
662647
{
663-
assert!(perm.is_initial());
648+
assert!(perm.permission.is_initial());
649+
max_sifa = cmp::max(max_sifa, perm.idempotent_foreign_access);
664650
for (_perms_range, perms) in self
665651
.rperms
666652
.iter_mut(Size::from_bytes(start) + base_offset, Size::from_bytes(end - start))
667653
{
668-
assert!(
669-
default_strongest_idempotent
670-
>= perm.permission.strongest_idempotent_foreign_access(protected)
671-
);
672654
perms.insert(idx, perm);
673655
}
674656
}
675657

676-
// Inserting the new perms might have broken the SIFA invariant (see `foreign_access_skipping.rs`).
677-
// We now weaken the recorded SIFA for our parents, until the invariant is restored.
678-
// We could weaken them all to `LocalAccess`, but it is more efficient to compute the SIFA
679-
// for the new permission statically, and use that.
680-
// See the comment in `tb_reborrow` for why it is correct to use the SIFA of `default_uninit_perm`.
681-
self.update_last_accessed_after_retag(parent_idx, default_strongest_idempotent);
658+
// Inserting the new perms might have broken the SIFA invariant (see
659+
// `foreign_access_skipping.rs`). We now weaken the recorded SIFA for our parents, until the
660+
// invariant is restored. We could weaken them all to `LocalAccess`, but it is more
661+
// efficient to compute the SIFA for the new permission statically, and use that. For this
662+
// we need the *maximum* SIFA (`Write` needs more fixup than `None`).
663+
self.update_last_accessed_after_retag(parent_idx, max_sifa);
682664

683665
interp_ok(())
684666
}
@@ -755,9 +737,9 @@ impl<'tcx> Tree {
755737
== Some(&ProtectorKind::StrongProtector)
756738
// Don't check for protector if it is a Cell (see `unsafe_cell_deallocate` in `interior_mutability.rs`).
757739
// Related to https://github.com/rust-lang/rust/issues/55005.
758-
&& !perm.permission().is_cell()
740+
&& !perm.permission.is_cell()
759741
// Only trigger UB if the accessed bit is set, i.e. if the protector is actually protecting this offset. See #4579.
760-
&& perm.is_accessed()
742+
&& perm.accessed
761743
{
762744
Err(TransitionError::ProtectedDealloc)
763745
} else {

src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ fn tree_compacting_is_sound() {
106106
as_foreign_or_child(rel),
107107
kind,
108108
parent.permission(),
109-
as_lazy_or_accessed(child.is_accessed()),
109+
as_lazy_or_accessed(child.accessed()),
110110
child.permission(),
111111
as_protected(child_protected),
112112
np.permission(),
@@ -122,7 +122,7 @@ fn tree_compacting_is_sound() {
122122
as_foreign_or_child(rel),
123123
kind,
124124
parent.permission(),
125-
as_lazy_or_accessed(child.is_accessed()),
125+
as_lazy_or_accessed(child.accessed()),
126126
child.permission(),
127127
as_protected(child_protected),
128128
nc.permission()
@@ -375,7 +375,7 @@ mod spurious_read {
375375

376376
impl LocStateProt {
377377
fn is_initial(&self) -> bool {
378-
self.state.is_initial()
378+
self.state.permission().is_initial()
379379
}
380380

381381
fn perform_access(&self, kind: AccessKind, rel: AccessRelatedness) -> Result<Self, ()> {

0 commit comments

Comments
 (0)