Skip to content

Commit

Permalink
Read on function exit should not be visible to children
Browse files Browse the repository at this point in the history
This fixes the issue introduced by the previous commit where an Active
would become Frozen because its parent was protected.
  • Loading branch information
Vanille-N committed Sep 20, 2023
1 parent 3492e7e commit f87e2e5
Showing 1 changed file with 60 additions and 1 deletion.
61 changes: 60 additions & 1 deletion src/borrow_tracker/tree_borrows/tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,63 @@ impl<'tree> TreeVisitor<'tree> {
}
Ok(())
}

// Applies `f_propagate` to every non-child vertex of the tree (ancestors first).
//
// `f_propagate` should follow the following format: for a given `Node` it updates its
// `Permission` depending on the position relative to `start` (given by an
// `AccessRelatedness`).
// It outputs whether the tree traversal for this subree should continue or not.
fn traverse_nonchildren<InnErr, OutErr>(
mut self,
start: BorTag,
f_propagate: impl Fn(NodeAppArgs<'_>) -> Result<ContinueTraversal, InnErr>,
err_builder: impl Fn(ErrHandlerArgs<'_, InnErr>) -> OutErr,
) -> Result<(), OutErr> {
let start_idx = self.tag_mapping.get(&start).unwrap();
let mut stack =
TreeVisitAux { accessed_tag: start_idx, f_propagate, err_builder, stack: Vec::new() };
{
let mut path_ascend = Vec::new();
// First climb to the root while recording the path
let mut curr = start_idx;
while let Some(ancestor) = self.nodes.get(curr).unwrap().parent {
path_ascend.push((ancestor, curr));
curr = ancestor;
}
// Then descend:
// - execute f_propagate on each node
// - record children in visit
while let Some((ancestor, next_in_path)) = path_ascend.pop() {
// Explore ancestors in descending order.
// `next_in_path` is excluded from the recursion because it
// will be the `ancestor` of the next iteration.
// It also needs a different `AccessRelatedness` than the other
// children of `ancestor`.
stack.exec_and_visit(
&mut self,
ancestor,
Some(next_in_path),
AccessRelatedness::StrictChildAccess,
)?;
}
};
// Up to this point we have never popped from `stack`, hence if the
// path to the root is `root = p(n) <- p(n-1)... <- p(1) <- p(0) = start`
// then now `stack` contains
// `[<children(p(n)) except p(n-1)> ... <children(p(1)) except p(0)>]`,
// all of which are for now unexplored.
// This is the starting point of a standard DFS which will thus
// explore all non-ancestors of `start` in the following order:
// - first the unexplored descendants of `parent(start)`;
// - then the unexplored descendants of `parent(parent(start))`;
// ...
// - until finally the unexplored descendants of `root`.
while let Some((tag, rel_pos)) = stack.pop() {
stack.exec_and_visit(&mut self, tag, None, rel_pos)?;
}
Ok(())
}
}

impl Tree {
Expand Down Expand Up @@ -605,6 +662,8 @@ impl<'tcx> Tree {
// This is a special access through the entire allocation.
// It actually only affects `initialized` locations, so we need
// to filter on those before initiating the traversal.
// In addition this implicit access should not be visible to children,
// thus the use of `traverse_nonchildren`.
for (perms_range, perms) in self.rperms.iter_mut_all() {
let idx = self.tag_mapping.get(&tag).unwrap();
if let Some(p) = perms.get(idx) {
Expand All @@ -616,7 +675,7 @@ impl<'tcx> Tree {
tag_mapping: &self.tag_mapping,
perms,
}
.traverse_parents_this_children_others(
.traverse_nonchildren(
tag,
|args| node_app(perms_range.clone(), args),
|args| err_handler(perms_range.clone(), args),
Expand Down

0 comments on commit f87e2e5

Please sign in to comment.