Skip to content

Commit 8ef2c6c

Browse files
TB: Make FnEntry access on protected locations be a write under certain circumstances
1 parent b0d791d commit 8ef2c6c

File tree

4 files changed

+35
-36
lines changed

4 files changed

+35
-36
lines changed

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

+4-3
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pub enum AccessCause {
1919
Explicit(AccessKind),
2020
Reborrow,
2121
Dealloc,
22-
FnExit,
22+
FnExit(AccessKind),
2323
}
2424

2525
impl fmt::Display for AccessCause {
@@ -28,7 +28,8 @@ impl fmt::Display for AccessCause {
2828
Self::Explicit(kind) => write!(f, "{kind}"),
2929
Self::Reborrow => write!(f, "reborrow"),
3030
Self::Dealloc => write!(f, "deallocation"),
31-
Self::FnExit => write!(f, "protector release"),
31+
Self::FnExit(AccessKind::Read) => write!(f, "protector release read"),
32+
Self::FnExit(AccessKind::Write) => write!(f, "protector release write"),
3233
}
3334
}
3435
}
@@ -40,7 +41,7 @@ impl AccessCause {
4041
Self::Explicit(kind) => format!("{rel} {kind}"),
4142
Self::Reborrow => format!("reborrow (acting as a {rel} read access)"),
4243
Self::Dealloc => format!("deallocation (acting as a {rel} write access)"),
43-
Self::FnExit => format!("protector release (acting as a {rel} read access)"),
44+
Self::FnExit(kind) => format!("protector release (acting as a {rel} {kind})"),
4445
}
4546
}
4647
}

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

+4-15
Original file line numberDiff line numberDiff line change
@@ -68,13 +68,11 @@ impl<'tcx> Tree {
6868
let global = machine.borrow_tracker.as_ref().unwrap();
6969
let span = machine.current_span();
7070
self.perform_access(
71-
access_kind,
7271
tag,
73-
Some(range),
72+
Some((range, access_kind, diagnostics::AccessCause::Explicit(access_kind))),
7473
global,
7574
alloc_id,
7675
span,
77-
diagnostics::AccessCause::Explicit(access_kind),
7876
)
7977
}
8078

@@ -115,15 +113,8 @@ impl<'tcx> Tree {
115113
alloc_id: AllocId, // diagnostics
116114
) -> InterpResult<'tcx> {
117115
let span = machine.current_span();
118-
self.perform_access(
119-
AccessKind::Read,
120-
tag,
121-
None, // no specified range because it occurs on the entire allocation
122-
global,
123-
alloc_id,
124-
span,
125-
diagnostics::AccessCause::FnExit,
126-
)
116+
// `None` makes it the magic on-protector-end operation
117+
self.perform_access(tag, None, global, alloc_id, span)
127118
}
128119
}
129120

@@ -297,13 +288,11 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
297288

298289
// All reborrows incur a (possibly zero-sized) read access to the parent
299290
tree_borrows.perform_access(
300-
AccessKind::Read,
301291
orig_tag,
302-
Some(range),
292+
Some((range, AccessKind::Read, diagnostics::AccessCause::Reborrow)),
303293
this.machine.borrow_tracker.as_ref().unwrap(),
304294
alloc_id,
305295
this.machine.current_span(),
306-
diagnostics::AccessCause::Reborrow,
307296
)?;
308297
// Record the parent-child pair in the tree.
309298
tree_borrows.new_child(orig_tag, new_tag, new_perm.initial_state, range, span)?;

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

+4
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,10 @@ impl Permission {
186186
pub fn is_disabled(&self) -> bool {
187187
self.inner == Disabled
188188
}
189+
/// Check if `self` is the post-child-write state of a pointer (is `Active`).
190+
pub fn is_active(&self) -> bool {
191+
self.inner == Active
192+
}
189193

190194
/// Default initial permission of the root of a new tree at inbounds positions.
191195
/// Must *only* be used for the root, this is not in general an "initial" permission!

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

+23-18
Original file line numberDiff line numberDiff line change
@@ -530,13 +530,11 @@ impl<'tcx> Tree {
530530
span: Span, // diagnostics
531531
) -> InterpResult<'tcx> {
532532
self.perform_access(
533-
AccessKind::Write,
534533
tag,
535-
Some(access_range),
534+
Some((access_range, AccessKind::Write, diagnostics::AccessCause::Dealloc)),
536535
global,
537536
alloc_id,
538537
span,
539-
diagnostics::AccessCause::Dealloc,
540538
)?;
541539
for (perms_range, perms) in self.rperms.iter_mut(access_range.start, access_range.size) {
542540
TreeVisitor { nodes: &mut self.nodes, tag_mapping: &self.tag_mapping, perms }
@@ -570,12 +568,16 @@ impl<'tcx> Tree {
570568
}
571569

572570
/// Map the per-node and per-location `LocationState::perform_access`
573-
/// to each location of `access_range`, on every tag of the allocation.
571+
/// to each location of the first component of `access_range_and_kind`,
572+
/// on every tag of the allocation.
574573
///
575-
/// If `access_range` is `None`, this is interpreted as the special
574+
/// If `access_range_and_kind` is `None`, this is interpreted as the special
576575
/// access that is applied on protector release:
577576
/// - the access will be applied only to initialized locations of the allocation,
578-
/// - and it will not be visible to children.
577+
/// - it will not be visible to children,
578+
/// - it will be recorded as a `FnExit` diagnostic access
579+
/// - and it will be a read except if the location is `Active`, i.e. has been written to,
580+
/// in which case it will be a write.
579581
///
580582
/// `LocationState::perform_access` will take care of raising transition
581583
/// errors and updating the `initialized` status of each location,
@@ -585,13 +587,11 @@ impl<'tcx> Tree {
585587
/// - recording the history.
586588
pub fn perform_access(
587589
&mut self,
588-
access_kind: AccessKind,
589590
tag: BorTag,
590-
access_range: Option<AllocRange>,
591+
access_range_and_kind: Option<(AllocRange, AccessKind, diagnostics::AccessCause)>,
591592
global: &GlobalState,
592-
alloc_id: AllocId, // diagnostics
593-
span: Span, // diagnostics
594-
access_cause: diagnostics::AccessCause, // diagnostics
593+
alloc_id: AllocId, // diagnostics
594+
span: Span, // diagnostics
595595
) -> InterpResult<'tcx> {
596596
use std::ops::Range;
597597
// Performs the per-node work:
@@ -605,6 +605,8 @@ impl<'tcx> Tree {
605605
// `perms_range` is only for diagnostics (it is the range of
606606
// the `RangeMap` on which we are currently working).
607607
let node_app = |perms_range: Range<u64>,
608+
access_kind: AccessKind,
609+
access_cause: diagnostics::AccessCause,
608610
args: NodeAppArgs<'_>|
609611
-> Result<ContinueTraversal, TransitionError> {
610612
let NodeAppArgs { node, mut perm, rel_pos } = args;
@@ -618,14 +620,13 @@ impl<'tcx> Tree {
618620

619621
let protected = global.borrow().protected_tags.contains_key(&node.tag);
620622
let transition = old_state.perform_access(access_kind, rel_pos, protected)?;
621-
622623
// Record the event as part of the history
623624
if !transition.is_noop() {
624625
node.debug_info.history.push(diagnostics::Event {
625626
transition,
626627
is_foreign: rel_pos.is_foreign(),
627628
access_cause,
628-
access_range,
629+
access_range: access_range_and_kind.map(|x| x.0),
629630
transition_range: perms_range,
630631
span,
631632
});
@@ -636,6 +637,7 @@ impl<'tcx> Tree {
636637
// Error handler in case `node_app` goes wrong.
637638
// Wraps the faulty transition in more context for diagnostics.
638639
let err_handler = |perms_range: Range<u64>,
640+
access_cause: diagnostics::AccessCause,
639641
args: ErrHandlerArgs<'_, TransitionError>|
640642
-> InterpError<'tcx> {
641643
let ErrHandlerArgs { error_kind, conflicting_info, accessed_info } = args;
@@ -650,16 +652,16 @@ impl<'tcx> Tree {
650652
.build()
651653
};
652654

653-
if let Some(access_range) = access_range {
655+
if let Some((access_range, access_kind, access_cause)) = access_range_and_kind {
654656
// Default branch: this is a "normal" access through a known range.
655657
// We iterate over affected locations and traverse the tree for each of them.
656658
for (perms_range, perms) in self.rperms.iter_mut(access_range.start, access_range.size)
657659
{
658660
TreeVisitor { nodes: &mut self.nodes, tag_mapping: &self.tag_mapping, perms }
659661
.traverse_parents_this_children_others(
660662
tag,
661-
|args| node_app(perms_range.clone(), args),
662-
|args| err_handler(perms_range.clone(), args),
663+
|args| node_app(perms_range.clone(), access_kind, access_cause, args),
664+
|args| err_handler(perms_range.clone(), access_cause, args),
663665
)?;
664666
}
665667
} else {
@@ -678,11 +680,14 @@ impl<'tcx> Tree {
678680
if let Some(p) = perms.get(idx)
679681
&& p.initialized
680682
{
683+
let access_kind =
684+
if p.permission.is_active() { AccessKind::Write } else { AccessKind::Read };
685+
let access_cause = diagnostics::AccessCause::FnExit(access_kind);
681686
TreeVisitor { nodes: &mut self.nodes, tag_mapping: &self.tag_mapping, perms }
682687
.traverse_nonchildren(
683688
tag,
684-
|args| node_app(perms_range.clone(), args),
685-
|args| err_handler(perms_range.clone(), args),
689+
|args| node_app(perms_range.clone(), access_kind, access_cause, args),
690+
|args| err_handler(perms_range.clone(), access_cause, args),
686691
)?;
687692
}
688693
}

0 commit comments

Comments
 (0)