Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 84 additions & 25 deletions src/borrow_tracker/tree_borrows/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,8 @@ struct DisplayFmtPadding {
indent_middle: S,
/// Indentation for the last child.
indent_last: S,
/// Replaces `join_last` for a wildcard root.
wildcard_root: S,
}
/// How to show whether a location has been accessed
///
Expand Down Expand Up @@ -561,6 +563,11 @@ impl DisplayFmt {
})
.unwrap_or("")
}

/// Print extra text if the tag is exposed.
fn print_exposed(&self, exposed: bool) -> S {
if exposed { " (exposed)" } else { "" }
}
}

/// Track the indentation of the tree.
Expand Down Expand Up @@ -607,23 +614,21 @@ fn char_repeat(c: char, n: usize) -> String {
struct DisplayRepr {
tag: BorTag,
name: Option<String>,
exposed: bool,
rperm: Vec<Option<LocationState>>,
children: Vec<DisplayRepr>,
}

impl DisplayRepr {
fn from(tree: &Tree, show_unnamed: bool) -> Option<Self> {
fn from(tree: &Tree, root: UniIndex, show_unnamed: bool) -> Option<Self> {
let mut v = Vec::new();
extraction_aux(tree, tree.root, show_unnamed, &mut v);
extraction_aux(tree, root, show_unnamed, &mut v);
let Some(root) = v.pop() else {
if show_unnamed {
unreachable!(
"This allocation contains no tags, not even a root. This should not happen."
);
}
eprintln!(
"This allocation does not contain named tags. Use `miri_print_borrow_state(_, true)` to also print unnamed tags."
);
return None;
};
assert!(v.is_empty());
Expand All @@ -637,6 +642,7 @@ impl DisplayRepr {
) {
let node = tree.nodes.get(idx).unwrap();
let name = node.debug_info.name.clone();
let exposed = node.is_exposed;
let children_sorted = {
let mut children = node.children.iter().cloned().collect::<Vec<_>>();
children.sort_by_key(|idx| tree.nodes.get(*idx).unwrap().tag);
Expand All @@ -661,12 +667,13 @@ impl DisplayRepr {
for child_idx in children_sorted {
extraction_aux(tree, child_idx, show_unnamed, &mut children);
}
acc.push(DisplayRepr { tag: node.tag, name, rperm, children });
acc.push(DisplayRepr { tag: node.tag, name, rperm, children, exposed });
}
}
}
fn print(
&self,
main_root: &Option<DisplayRepr>,
wildcard_subtrees: &[DisplayRepr],
fmt: &DisplayFmt,
indenter: &mut DisplayIndent,
protected_tags: &FxHashMap<BorTag, ProtectorKind>,
Expand Down Expand Up @@ -703,15 +710,41 @@ impl DisplayRepr {
block.push(s);
}
// This is the actual work
print_aux(
self,
&range_padding,
fmt,
indenter,
protected_tags,
true, /* root _is_ the last child */
&mut block,
);
if let Some(root) = main_root {
print_aux(
root,
&range_padding,
fmt,
indenter,
protected_tags,
true, /* root _is_ the last child */
false, /* not a wildcard_root*/
&mut block,
);
}
for tree in wildcard_subtrees.iter() {
let mut gap_line = String::new();
gap_line.push_str(fmt.perm.open);
for (i, &pad) in range_padding.iter().enumerate() {
if i > 0 {
gap_line.push_str(fmt.perm.sep);
}
gap_line.push_str(&format!("{}{}", char_repeat(' ', pad), " "));
}
gap_line.push_str(fmt.perm.close);
block.push(gap_line);

print_aux(
tree,
&range_padding,
fmt,
indenter,
protected_tags,
true, /* root _is_ the last child */
true, /* wildcard_root*/
&mut block,
);
}
// Then it's just prettifying it with a border of dashes.
{
let wr = &fmt.wrapper;
Expand Down Expand Up @@ -741,6 +774,7 @@ impl DisplayRepr {
indent: &mut DisplayIndent,
protected_tags: &FxHashMap<BorTag, ProtectorKind>,
is_last_child: bool,
is_wildcard_root: bool,
acc: &mut Vec<String>,
) {
let mut line = String::new();
Expand All @@ -760,7 +794,9 @@ impl DisplayRepr {
indent.write(&mut line);
{
// padding
line.push_str(if is_last_child {
line.push_str(if is_wildcard_root {
fmt.padding.wildcard_root
} else if is_last_child {
fmt.padding.join_last
} else {
fmt.padding.join_middle
Expand All @@ -777,12 +813,22 @@ impl DisplayRepr {
line.push_str(&fmt.print_tag(tree.tag, &tree.name));
let protector = protected_tags.get(&tree.tag);
line.push_str(fmt.print_protector(protector));
line.push_str(fmt.print_exposed(tree.exposed));
// Push the line to the accumulator then recurse.
acc.push(line);
let nb_children = tree.children.len();
for (i, child) in tree.children.iter().enumerate() {
indent.increment(fmt, is_last_child);
print_aux(child, padding, fmt, indent, protected_tags, i + 1 == nb_children, acc);
print_aux(
child,
padding,
fmt,
indent,
protected_tags,
/* is_last_child */ i + 1 == nb_children,
/* is_wildcard_root */ false,
acc,
);
indent.decrement(fmt);
}
}
Expand All @@ -803,6 +849,7 @@ const DEFAULT_FORMATTER: DisplayFmt = DisplayFmt {
indent_last: " ",
join_haschild: "┬",
join_default: "─",
wildcard_root: "*",
},
accessed: DisplayFmtAccess { yes: " ", no: "?", meh: "-" },
};
Expand All @@ -816,15 +863,27 @@ impl<'tcx> Tree {
) -> InterpResult<'tcx> {
let mut indenter = DisplayIndent::new();
let ranges = self.locations.iter_all().map(|(range, _loc)| range).collect::<Vec<_>>();
if let Some(repr) = DisplayRepr::from(self, show_unnamed) {
repr.print(
&DEFAULT_FORMATTER,
&mut indenter,
protected_tags,
ranges,
/* print warning message about tags not shown */ !show_unnamed,
let main_tree = DisplayRepr::from(self, self.roots[0], show_unnamed);
let wildcard_subtrees = self.roots[1..]
.iter()
.filter_map(|root| DisplayRepr::from(self, *root, show_unnamed))
.collect::<Vec<_>>();

if main_tree.is_none() && wildcard_subtrees.is_empty() {
eprintln!(
"This allocation does not contain named tags. Use `miri_print_borrow_state(_, true)` to also print unnamed tags."
);
}

DisplayRepr::print(
&main_tree,
wildcard_subtrees.as_slice(),
&DEFAULT_FORMATTER,
&mut indenter,
protected_tags,
ranges,
/* print warning message about tags not shown */ !show_unnamed,
);
interp_ok(())
}
}
15 changes: 5 additions & 10 deletions src/borrow_tracker/tree_borrows/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,18 +239,14 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
return interp_ok(new_prov);
}
};
let new_prov = Provenance::Concrete { alloc_id, tag: new_tag };

log_creation(this, Some((alloc_id, base_offset, parent_prov)))?;

let orig_tag = match parent_prov {
ProvenanceExtra::Wildcard => return interp_ok(place.ptr().provenance), // TODO: handle retagging wildcard pointers
ProvenanceExtra::Concrete(tag) => tag,
};

trace!(
"reborrow: reference {:?} derived from {:?} (pointee {}): {:?}, size {}",
new_tag,
orig_tag,
parent_prov,
place.layout.ty,
interpret::Pointer::new(alloc_id, base_offset),
ptr_size.bytes()
Expand Down Expand Up @@ -281,7 +277,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
assert_eq!(ptr_size, Size::ZERO); // we did the deref check above, size has to be 0 here
// There's not actually any bytes here where accesses could even be tracked.
// Just produce the new provenance, nothing else to do.
return interp_ok(Some(Provenance::Concrete { alloc_id, tag: new_tag }));
return interp_ok(Some(new_prov));
}

let protected = new_perm.protector.is_some();
Expand Down Expand Up @@ -367,11 +363,10 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
}
}
}

// Record the parent-child pair in the tree.
tree_borrows.new_child(
base_offset,
orig_tag,
parent_prov,
new_tag,
inside_perms,
new_perm.outside_perm,
Expand All @@ -380,7 +375,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
)?;
drop(tree_borrows);

interp_ok(Some(Provenance::Concrete { alloc_id, tag: new_tag }))
interp_ok(Some(new_prov))
}

fn tb_retag_place(
Expand Down
Loading