Make TB tree traversal bottom-up
In preparation for #3837, the tree traversal needs to be made bottom-up, because the current top-down tree traversal, coupled with that PR's changes to the garbage collector, can introduce non-deterministic error messages if the GC removes a parent tag of the accessed tag that would have triggered the error first. This is a breaking change for the diagnostics emitted by TB. The implemented semantics stay the same.
This commit is contained in:
parent
9b82f3b729
commit
2765444c15
@ -149,12 +149,11 @@ fn perform_access(
|
||||
// is possible, it also updates the internal state to keep track of whether
|
||||
// the propagation can be skipped next time.
|
||||
// It is a performance loss not to call this function when a foreign access occurs.
|
||||
// It is unsound not to call this function when a child access occurs.
|
||||
// FIXME: This optimization is wrong, and is currently disabled (by ignoring the
|
||||
// result returned here). Since we presumably want an optimization like this,
|
||||
// we should add it back. See #3864 for more information.
|
||||
fn update_last_foreign_access(
|
||||
&mut self,
|
||||
fn skip_if_known_noop(
|
||||
&self,
|
||||
access_kind: AccessKind,
|
||||
rel_pos: AccessRelatedness,
|
||||
) -> ContinueTraversal {
|
||||
@ -177,22 +176,37 @@ fn update_last_foreign_access(
|
||||
// No need to update `self.latest_foreign_access`,
|
||||
// the type of the current streak among nonempty read-only
|
||||
// or nonempty with at least one write has not changed.
|
||||
ContinueTraversal::SkipChildren
|
||||
ContinueTraversal::SkipSelfAndChildren
|
||||
} else {
|
||||
// Otherwise propagate this time, and also record the
|
||||
// access that just occurred so that we can skip the propagation
|
||||
// next time.
|
||||
self.latest_foreign_access = Some(access_kind);
|
||||
ContinueTraversal::Recurse
|
||||
}
|
||||
} else {
|
||||
// A child access occurred, this breaks the streak of foreign
|
||||
// accesses in a row and the sequence since the previous child access
|
||||
// is now empty.
|
||||
self.latest_foreign_access = None;
|
||||
ContinueTraversal::Recurse
|
||||
}
|
||||
}
|
||||
|
||||
/// Records a new access, so that future access can potentially be skipped
|
||||
/// by `skip_if_known_noop`.
|
||||
/// The invariants for this function are closely coupled to the function above:
|
||||
/// It MUST be called on child accesses, and on foreign accesses MUST be called
|
||||
/// when `skip_if_know_noop` returns `Recurse`, and MUST NOT be called otherwise.
|
||||
/// FIXME: This optimization is wrong, and is currently disabled (by ignoring the
|
||||
/// result returned here). Since we presumably want an optimization like this,
|
||||
/// we should add it back. See #3864 for more information.
|
||||
#[allow(unused)]
|
||||
fn record_new_access(&mut self, access_kind: AccessKind, rel_pos: AccessRelatedness) {
|
||||
if rel_pos.is_foreign() {
|
||||
self.latest_foreign_access = Some(access_kind);
|
||||
} else {
|
||||
self.latest_foreign_access = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for LocationState {
|
||||
@ -285,13 +299,16 @@ struct TreeVisitor<'tree> {
|
||||
/// Whether to continue exploring the children recursively or not.
|
||||
enum ContinueTraversal {
|
||||
Recurse,
|
||||
SkipChildren,
|
||||
SkipSelfAndChildren,
|
||||
}
|
||||
|
||||
/// Stack of nodes left to explore in a tree traversal.
|
||||
struct TreeVisitorStack<NodeApp, ErrHandler> {
|
||||
struct TreeVisitorStack<NodeContinue, NodeApp, ErrHandler> {
|
||||
/// Identifier of the original access.
|
||||
initial: UniIndex,
|
||||
/// Function describing whether to continue at a tag.
|
||||
/// This is only invoked for foreign accesses.
|
||||
f_continue: NodeContinue,
|
||||
/// Function to apply to each tag.
|
||||
f_propagate: NodeApp,
|
||||
/// Handler to add the required context to diagnostics.
|
||||
@ -299,152 +316,178 @@ struct TreeVisitorStack<NodeApp, ErrHandler> {
|
||||
/// Mutable state of the visit: the tags left to handle.
|
||||
/// Every tag pushed should eventually be handled,
|
||||
/// and the precise order is relevant for diagnostics.
|
||||
stack: Vec<(UniIndex, AccessRelatedness)>,
|
||||
/// Since the traversal is bottom-up, we need to remember
|
||||
/// whether we're here initially (false) or after visiting all
|
||||
/// children (true). The bool indicates this.
|
||||
stack: Vec<(UniIndex, AccessRelatedness, bool)>,
|
||||
}
|
||||
|
||||
impl<NodeApp, InnErr, OutErr, ErrHandler> TreeVisitorStack<NodeApp, ErrHandler>
|
||||
impl<NodeContinue, NodeApp, InnErr, OutErr, ErrHandler>
|
||||
TreeVisitorStack<NodeContinue, NodeApp, ErrHandler>
|
||||
where
|
||||
NodeApp: Fn(NodeAppArgs<'_>) -> Result<ContinueTraversal, InnErr>,
|
||||
NodeContinue: Fn(&NodeAppArgs<'_>) -> ContinueTraversal,
|
||||
NodeApp: Fn(NodeAppArgs<'_>) -> Result<(), InnErr>,
|
||||
ErrHandler: Fn(ErrHandlerArgs<'_, InnErr>) -> OutErr,
|
||||
{
|
||||
/// Apply the function to the current `tag`, and push its children
|
||||
/// to the stack of future tags to visit.
|
||||
fn exec_and_visit(
|
||||
fn should_continue_at(
|
||||
&self,
|
||||
this: &mut TreeVisitor<'_>,
|
||||
idx: UniIndex,
|
||||
rel_pos: AccessRelatedness,
|
||||
) -> ContinueTraversal {
|
||||
let node = this.nodes.get_mut(idx).unwrap();
|
||||
let args = NodeAppArgs { node, perm: this.perms.entry(idx), rel_pos };
|
||||
(self.f_continue)(&args)
|
||||
}
|
||||
|
||||
fn propagate_at(
|
||||
&mut self,
|
||||
this: &mut TreeVisitor<'_>,
|
||||
idx: UniIndex,
|
||||
exclude: Option<UniIndex>,
|
||||
rel_pos: AccessRelatedness,
|
||||
) -> Result<(), OutErr> {
|
||||
// 1. apply the propagation function
|
||||
let node = this.nodes.get_mut(idx).unwrap();
|
||||
let recurse =
|
||||
(self.f_propagate)(NodeAppArgs { node, perm: this.perms.entry(idx), rel_pos })
|
||||
.map_err(|error_kind| {
|
||||
(self.err_builder)(ErrHandlerArgs {
|
||||
error_kind,
|
||||
conflicting_info: &this.nodes.get(idx).unwrap().debug_info,
|
||||
accessed_info: &this.nodes.get(self.initial).unwrap().debug_info,
|
||||
})
|
||||
})?;
|
||||
let node = this.nodes.get(idx).unwrap();
|
||||
// 2. add the children to the stack for future traversal
|
||||
if matches!(recurse, ContinueTraversal::Recurse) {
|
||||
let general_child_rel = rel_pos.for_child();
|
||||
for &child in node.children.iter() {
|
||||
// Some child might be excluded from here and handled separately,
|
||||
// e.g. the initially accessed tag.
|
||||
if Some(child) != exclude {
|
||||
// We should still ensure that if we don't skip the initially accessed
|
||||
// it will receive the proper `AccessRelatedness`.
|
||||
let this_child_rel = if child == self.initial {
|
||||
AccessRelatedness::This
|
||||
} else {
|
||||
general_child_rel
|
||||
};
|
||||
self.stack.push((child, this_child_rel));
|
||||
(self.f_propagate)(NodeAppArgs { node, perm: this.perms.entry(idx), rel_pos }).map_err(
|
||||
|error_kind| {
|
||||
(self.err_builder)(ErrHandlerArgs {
|
||||
error_kind,
|
||||
conflicting_info: &this.nodes.get(idx).unwrap().debug_info,
|
||||
accessed_info: &this.nodes.get(self.initial).unwrap().debug_info,
|
||||
})
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn go_upwards_from_accessed(
|
||||
&mut self,
|
||||
this: &mut TreeVisitor<'_>,
|
||||
accessed_node: UniIndex,
|
||||
push_children_of_accessed: bool,
|
||||
) -> Result<(), OutErr> {
|
||||
assert!(self.stack.is_empty());
|
||||
// First, handle accessed node. A bunch of things need to
|
||||
// be handled differently here compared to the further parents
|
||||
// of `accesssed_node`.
|
||||
{
|
||||
self.propagate_at(this, accessed_node, AccessRelatedness::This)?;
|
||||
if push_children_of_accessed {
|
||||
let accessed_node = this.nodes.get(accessed_node).unwrap();
|
||||
for &child in accessed_node.children.iter().rev() {
|
||||
self.stack.push((child, AccessRelatedness::AncestorAccess, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Then, handle the accessed node's parent. Here, we need to
|
||||
// make sure we only mark the "cousin" subtrees for later visitation,
|
||||
// not the subtree that contains the accessed node.
|
||||
let mut last_node = accessed_node;
|
||||
while let Some(current) = this.nodes.get(last_node).unwrap().parent {
|
||||
self.propagate_at(this, current, AccessRelatedness::StrictChildAccess)?;
|
||||
let node = this.nodes.get(current).unwrap();
|
||||
for &child in node.children.iter().rev() {
|
||||
if last_node == child {
|
||||
continue;
|
||||
}
|
||||
self.stack.push((child, AccessRelatedness::DistantAccess, false));
|
||||
}
|
||||
last_node = current;
|
||||
}
|
||||
self.stack.reverse();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn finish_foreign_accesses(&mut self, this: &mut TreeVisitor<'_>) -> Result<(), OutErr> {
|
||||
while let Some((idx, rel_pos, is_final)) = self.stack.last_mut() {
|
||||
let idx = *idx;
|
||||
let rel_pos = *rel_pos;
|
||||
if *is_final {
|
||||
self.stack.pop();
|
||||
self.propagate_at(this, idx, rel_pos)?;
|
||||
} else {
|
||||
*is_final = true;
|
||||
let handle_children = self.should_continue_at(this, idx, rel_pos);
|
||||
match handle_children {
|
||||
ContinueTraversal::Recurse => {
|
||||
// add all children, and also leave the node itself
|
||||
// on the stack so that it can be visited later.
|
||||
let node = this.nodes.get(idx).unwrap();
|
||||
for &child in node.children.iter() {
|
||||
self.stack.push((child, rel_pos, false));
|
||||
}
|
||||
}
|
||||
ContinueTraversal::SkipSelfAndChildren => {
|
||||
// skip self
|
||||
self.stack.pop();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn new(initial: UniIndex, f_propagate: NodeApp, err_builder: ErrHandler) -> Self {
|
||||
Self { initial, f_propagate, err_builder, stack: Vec::new() }
|
||||
}
|
||||
|
||||
/// Finish the exploration by applying `exec_and_visit` until
|
||||
/// the stack is empty.
|
||||
fn finish(&mut self, visitor: &mut TreeVisitor<'_>) -> Result<(), OutErr> {
|
||||
while let Some((idx, rel_pos)) = self.stack.pop() {
|
||||
self.exec_and_visit(visitor, idx, /* no children to exclude */ None, rel_pos)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Push all ancestors to the exploration stack in order of nearest ancestor
|
||||
/// towards the top.
|
||||
fn push_and_visit_strict_ancestors(
|
||||
&mut self,
|
||||
visitor: &mut TreeVisitor<'_>,
|
||||
) -> Result<(), OutErr> {
|
||||
let mut path_ascend = Vec::new();
|
||||
// First climb to the root while recording the path
|
||||
let mut curr = self.initial;
|
||||
while let Some(ancestor) = visitor.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`.
|
||||
self.exec_and_visit(
|
||||
visitor,
|
||||
ancestor,
|
||||
Some(next_in_path),
|
||||
AccessRelatedness::StrictChildAccess,
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
fn new(
|
||||
initial: UniIndex,
|
||||
f_continue: NodeContinue,
|
||||
f_propagate: NodeApp,
|
||||
err_builder: ErrHandler,
|
||||
) -> Self {
|
||||
Self { initial, f_continue, f_propagate, err_builder, stack: Vec::new() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tree> TreeVisitor<'tree> {
|
||||
// Applies `f_propagate` to every vertex of the tree top-down in the following order: first
|
||||
// all ancestors of `start`, then `start` itself, then children of `start`, then the rest.
|
||||
// Applies `f_propagate` to every vertex of the tree bottom-up in the following order: first
|
||||
// all ancestors of `start` (starting with `start` itself), then children of `start`, then the rest,
|
||||
// always going bottom-up.
|
||||
// This ensures that errors are triggered in the following order
|
||||
// - first invalid accesses with insufficient permissions, closest to the root first,
|
||||
// - then protector violations, closest to `start` first.
|
||||
// - first invalid accesses with insufficient permissions, closest to the accessed node first,
|
||||
// - then protector violations, bottom-up, starting with the children of the accessed node, and then
|
||||
// going upwards and outwards.
|
||||
//
|
||||
// `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_parents_this_children_others<InnErr, OutErr>(
|
||||
// `f_continue` is called before on foreign nodes, and describes whether to continue
|
||||
// with the subtree at that node.
|
||||
fn traverse_this_parents_children_other<InnErr, OutErr>(
|
||||
mut self,
|
||||
start: BorTag,
|
||||
f_propagate: impl Fn(NodeAppArgs<'_>) -> Result<ContinueTraversal, InnErr>,
|
||||
f_continue: impl Fn(&NodeAppArgs<'_>) -> ContinueTraversal,
|
||||
f_propagate: impl Fn(NodeAppArgs<'_>) -> Result<(), InnErr>,
|
||||
err_builder: impl Fn(ErrHandlerArgs<'_, InnErr>) -> OutErr,
|
||||
) -> Result<(), OutErr> {
|
||||
let start_idx = self.tag_mapping.get(&start).unwrap();
|
||||
let mut stack = TreeVisitorStack::new(start_idx, f_propagate, err_builder);
|
||||
stack.push_and_visit_strict_ancestors(&mut self)?;
|
||||
// All (potentially zero) ancestors have been explored,
|
||||
// it's time to explore the `start` tag.
|
||||
stack.exec_and_visit(
|
||||
&mut self,
|
||||
start_idx,
|
||||
/* no children to exclude */ None,
|
||||
AccessRelatedness::This,
|
||||
)?;
|
||||
// Then finish with a normal DFS.
|
||||
stack.finish(&mut self)
|
||||
let mut stack = TreeVisitorStack::new(start_idx, f_continue, f_propagate, err_builder);
|
||||
// Visits the accessed node itself, and all its parents, i.e. all nodes
|
||||
// undergoing a child access. Also pushes the children and the other
|
||||
// cousin nodes (i.e. all nodes undergoing a foreign access) to the stack
|
||||
// to be processed later.
|
||||
stack.go_upwards_from_accessed(&mut self, start_idx, true)?;
|
||||
// Now visit all the foreign nodes we remembered earlier.
|
||||
// For this we go bottom-up, but also allow f_continue to skip entire
|
||||
// subtrees from being visited if it would be a NOP.
|
||||
stack.finish_foreign_accesses(&mut self)
|
||||
}
|
||||
|
||||
// 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.
|
||||
// Like `traverse_this_parents_children_other`, but skips the children of `start`.
|
||||
fn traverse_nonchildren<InnErr, OutErr>(
|
||||
mut self,
|
||||
start: BorTag,
|
||||
f_propagate: impl Fn(NodeAppArgs<'_>) -> Result<ContinueTraversal, InnErr>,
|
||||
f_continue: impl Fn(&NodeAppArgs<'_>) -> ContinueTraversal,
|
||||
f_propagate: impl Fn(NodeAppArgs<'_>) -> Result<(), InnErr>,
|
||||
err_builder: impl Fn(ErrHandlerArgs<'_, InnErr>) -> OutErr,
|
||||
) -> Result<(), OutErr> {
|
||||
let start_idx = self.tag_mapping.get(&start).unwrap();
|
||||
let mut stack = TreeVisitorStack::new(start_idx, f_propagate, err_builder);
|
||||
stack.push_and_visit_strict_ancestors(&mut self)?;
|
||||
// We *don't* visit the `start` tag, and we don't push its children.
|
||||
// Only finish the DFS with the cousins.
|
||||
stack.finish(&mut self)
|
||||
let mut stack = TreeVisitorStack::new(start_idx, f_continue, f_propagate, err_builder);
|
||||
// Visits the accessed node itself, and all its parents, i.e. all nodes
|
||||
// undergoing a child access. Also pushes the other cousin nodes to the
|
||||
// stack, but not the children of the accessed node.
|
||||
stack.go_upwards_from_accessed(&mut self, start_idx, false)?;
|
||||
// Now visit all the foreign nodes we remembered earlier.
|
||||
// For this we go bottom-up, but also allow f_continue to skip entire
|
||||
// subtrees from being visited if it would be a NOP.
|
||||
stack.finish_foreign_accesses(&mut self)
|
||||
}
|
||||
}
|
||||
|
||||
@ -541,16 +584,18 @@ pub fn dealloc(
|
||||
)?;
|
||||
for (perms_range, perms) in self.rperms.iter_mut(access_range.start, access_range.size) {
|
||||
TreeVisitor { nodes: &mut self.nodes, tag_mapping: &self.tag_mapping, perms }
|
||||
.traverse_parents_this_children_others(
|
||||
.traverse_this_parents_children_other(
|
||||
tag,
|
||||
|args: NodeAppArgs<'_>| -> Result<ContinueTraversal, TransitionError> {
|
||||
// visit all children, skipping none
|
||||
|_| ContinueTraversal::Recurse,
|
||||
|args: NodeAppArgs<'_>| -> Result<(), TransitionError> {
|
||||
let NodeAppArgs { node, .. } = args;
|
||||
if global.borrow().protected_tags.get(&node.tag)
|
||||
== Some(&ProtectorKind::StrongProtector)
|
||||
{
|
||||
Err(TransitionError::ProtectedDealloc)
|
||||
} else {
|
||||
Ok(ContinueTraversal::Recurse)
|
||||
Ok(())
|
||||
}
|
||||
},
|
||||
|args: ErrHandlerArgs<'_, TransitionError>| -> InterpError<'tcx> {
|
||||
@ -607,16 +652,28 @@ pub fn perform_access(
|
||||
//
|
||||
// `perms_range` is only for diagnostics (it is the range of
|
||||
// the `RangeMap` on which we are currently working).
|
||||
let node_skipper = |access_kind: AccessKind, args: &NodeAppArgs<'_>| -> ContinueTraversal {
|
||||
let NodeAppArgs { node, perm, rel_pos } = args;
|
||||
|
||||
let old_state = perm
|
||||
.get()
|
||||
.copied()
|
||||
.unwrap_or_else(|| LocationState::new_uninit(node.default_initial_perm));
|
||||
// FIXME: See #3684
|
||||
let _would_skip_if_not_for_fixme = old_state.skip_if_known_noop(access_kind, *rel_pos);
|
||||
ContinueTraversal::Recurse
|
||||
};
|
||||
let node_app = |perms_range: Range<u64>,
|
||||
access_kind: AccessKind,
|
||||
access_cause: diagnostics::AccessCause,
|
||||
args: NodeAppArgs<'_>|
|
||||
-> Result<ContinueTraversal, TransitionError> {
|
||||
-> Result<(), TransitionError> {
|
||||
let NodeAppArgs { node, mut perm, rel_pos } = args;
|
||||
|
||||
let old_state = perm.or_insert(LocationState::new_uninit(node.default_initial_perm));
|
||||
|
||||
old_state.update_last_foreign_access(access_kind, rel_pos);
|
||||
// FIXME: See #3684
|
||||
// old_state.record_new_access(access_kind, rel_pos);
|
||||
|
||||
let protected = global.borrow().protected_tags.contains_key(&node.tag);
|
||||
let transition = old_state.perform_access(access_kind, rel_pos, protected)?;
|
||||
@ -631,7 +688,7 @@ pub fn perform_access(
|
||||
span,
|
||||
});
|
||||
}
|
||||
Ok(ContinueTraversal::Recurse)
|
||||
Ok(())
|
||||
};
|
||||
|
||||
// Error handler in case `node_app` goes wrong.
|
||||
@ -658,8 +715,9 @@ pub fn perform_access(
|
||||
for (perms_range, perms) in self.rperms.iter_mut(access_range.start, access_range.size)
|
||||
{
|
||||
TreeVisitor { nodes: &mut self.nodes, tag_mapping: &self.tag_mapping, perms }
|
||||
.traverse_parents_this_children_others(
|
||||
.traverse_this_parents_children_other(
|
||||
tag,
|
||||
|args| node_skipper(access_kind, args),
|
||||
|args| node_app(perms_range.clone(), access_kind, access_cause, args),
|
||||
|args| err_handler(perms_range.clone(), access_cause, args),
|
||||
)?;
|
||||
@ -686,6 +744,7 @@ pub fn perform_access(
|
||||
TreeVisitor { nodes: &mut self.nodes, tag_mapping: &self.tag_mapping, perms }
|
||||
.traverse_nonchildren(
|
||||
tag,
|
||||
|args| node_skipper(access_kind, args),
|
||||
|args| node_app(perms_range.clone(), access_kind, access_cause, args),
|
||||
|args| err_handler(perms_range.clone(), access_cause, args),
|
||||
)?;
|
||||
|
@ -221,6 +221,10 @@ pub fn or_insert(&mut self, default: V) -> &mut V {
|
||||
}
|
||||
self.inner.as_mut().unwrap()
|
||||
}
|
||||
|
||||
pub fn get(&self) -> Option<&V> {
|
||||
self.inner.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
mod tests {
|
||||
|
@ -5,24 +5,18 @@ LL | let _val = *target_alias;
|
||||
| ^^^^^^^^^^^^^ read access through <TAG> at ALLOC[0x0] is forbidden
|
||||
|
|
||||
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
|
||||
= help: the accessed tag <TAG> is a child of the conflicting tag <TAG>
|
||||
= help: the conflicting tag <TAG> has state Disabled which forbids this child read access
|
||||
help: the accessed tag <TAG> was created here
|
||||
= help: the accessed tag <TAG> has state Disabled which forbids this child read access
|
||||
help: the accessed tag <TAG> was created here, in the initial state Frozen
|
||||
--> $DIR/alias_through_mutation.rs:LL:CC
|
||||
|
|
||||
LL | *x = &mut *(target as *mut _);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: the conflicting tag <TAG> was created here, in the initial state Reserved
|
||||
--> $DIR/alias_through_mutation.rs:LL:CC
|
||||
|
|
||||
LL | retarget(&mut target_alias, target);
|
||||
| ^^^^^^
|
||||
help: the conflicting tag <TAG> later transitioned to Disabled due to a foreign write access at offsets [0x0..0x4]
|
||||
help: the accessed tag <TAG> later transitioned to Disabled due to a foreign write access at offsets [0x0..0x4]
|
||||
--> $DIR/alias_through_mutation.rs:LL:CC
|
||||
|
|
||||
LL | *target = 13;
|
||||
| ^^^^^^^^^^^^
|
||||
= help: this transition corresponds to a loss of read and write permissions
|
||||
= help: this transition corresponds to a loss of read permissions
|
||||
= note: BACKTRACE (of the first span):
|
||||
= note: inside `main` at $DIR/alias_through_mutation.rs:LL:CC
|
||||
|
||||
|
@ -5,19 +5,13 @@ LL | *LEAK = 7;
|
||||
| ^^^^^^^^^ write access through <TAG> at ALLOC[0x0] is forbidden
|
||||
|
|
||||
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
|
||||
= help: the accessed tag <TAG> is a child of the conflicting tag <TAG>
|
||||
= help: the conflicting tag <TAG> has state Disabled which forbids this child write access
|
||||
help: the accessed tag <TAG> was created here
|
||||
= help: the accessed tag <TAG> has state Disabled which forbids this child write access
|
||||
help: the accessed tag <TAG> was created here, in the initial state Frozen
|
||||
--> $DIR/box_exclusive_violation1.rs:LL:CC
|
||||
|
|
||||
LL | fn unknown_code_1(x: &i32) {
|
||||
| ^
|
||||
help: the conflicting tag <TAG> was created here, in the initial state Frozen
|
||||
--> $DIR/box_exclusive_violation1.rs:LL:CC
|
||||
|
|
||||
LL | unknown_code_1(&*our);
|
||||
| ^^^^^
|
||||
help: the conflicting tag <TAG> later transitioned to Disabled due to a foreign write access at offsets [0x0..0x4]
|
||||
help: the accessed tag <TAG> later transitioned to Disabled due to a foreign write access at offsets [0x0..0x4]
|
||||
--> $DIR/box_exclusive_violation1.rs:LL:CC
|
||||
|
|
||||
LL | *our = 5;
|
||||
|
@ -5,19 +5,13 @@ LL | v2[1] = 7;
|
||||
| ^^^^^^^^^ write access through <TAG> at ALLOC[0x4] is forbidden
|
||||
|
|
||||
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
|
||||
= help: the accessed tag <TAG> is a child of the conflicting tag <TAG>
|
||||
= help: the conflicting tag <TAG> has state Disabled which forbids this child write access
|
||||
help: the accessed tag <TAG> was created here
|
||||
= help: the accessed tag <TAG> has state Disabled which forbids this child write access
|
||||
help: the accessed tag <TAG> was created here, in the initial state Reserved
|
||||
--> $DIR/buggy_as_mut_slice.rs:LL:CC
|
||||
|
|
||||
LL | let v2 = safe::as_mut_slice(&v);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: the conflicting tag <TAG> was created here, in the initial state Reserved
|
||||
--> $DIR/buggy_as_mut_slice.rs:LL:CC
|
||||
|
|
||||
LL | unsafe { from_raw_parts_mut(self_.as_ptr() as *mut T, self_.len()) }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: the conflicting tag <TAG> later transitioned to Disabled due to a foreign write access at offsets [0x4..0x8]
|
||||
help: the accessed tag <TAG> later transitioned to Disabled due to a foreign write access at offsets [0x4..0x8]
|
||||
--> $DIR/buggy_as_mut_slice.rs:LL:CC
|
||||
|
|
||||
LL | v1[1] = 5;
|
||||
|
@ -5,19 +5,13 @@ LL | b[1] = 6;
|
||||
| ^^^^^^^^ write access through <TAG> at ALLOC[0x4] is forbidden
|
||||
|
|
||||
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
|
||||
= help: the accessed tag <TAG> is a child of the conflicting tag <TAG>
|
||||
= help: the conflicting tag <TAG> has state Disabled which forbids this child write access
|
||||
help: the accessed tag <TAG> was created here
|
||||
= help: the accessed tag <TAG> has state Disabled which forbids this child write access
|
||||
help: the accessed tag <TAG> was created here, in the initial state Reserved
|
||||
--> $DIR/buggy_split_at_mut.rs:LL:CC
|
||||
|
|
||||
LL | let (a, b) = safe::split_at_mut(&mut array, 0);
|
||||
| ^
|
||||
help: the conflicting tag <TAG> was created here, in the initial state Reserved
|
||||
--> $DIR/buggy_split_at_mut.rs:LL:CC
|
||||
|
|
||||
LL | from_raw_parts_mut(ptr.offset(mid as isize), len - mid),
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: the conflicting tag <TAG> later transitioned to Disabled due to a foreign write access at offsets [0x4..0x8]
|
||||
help: the accessed tag <TAG> later transitioned to Disabled due to a foreign write access at offsets [0x4..0x8]
|
||||
--> $DIR/buggy_split_at_mut.rs:LL:CC
|
||||
|
|
||||
LL | a[1] = 5;
|
||||
|
@ -5,19 +5,13 @@ LL | let _val = *xref;
|
||||
| ^^^^^ read access through <TAG> at ALLOC[0x0] is forbidden
|
||||
|
|
||||
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
|
||||
= help: the accessed tag <TAG> is a child of the conflicting tag <TAG>
|
||||
= help: the conflicting tag <TAG> has state Disabled which forbids this child read access
|
||||
help: the accessed tag <TAG> was created here
|
||||
= help: the accessed tag <TAG> has state Disabled which forbids this child read access
|
||||
help: the accessed tag <TAG> was created here, in the initial state Reserved
|
||||
--> $DIR/illegal_write5.rs:LL:CC
|
||||
|
|
||||
LL | let xref = unsafe { &mut *xraw };
|
||||
| ^^^^^^^^^^
|
||||
help: the conflicting tag <TAG> was created here, in the initial state Reserved
|
||||
--> $DIR/illegal_write5.rs:LL:CC
|
||||
|
|
||||
LL | let xref = unsafe { &mut *xraw };
|
||||
| ^^^^^^^^^^
|
||||
help: the conflicting tag <TAG> later transitioned to Disabled due to a foreign write access at offsets [0x0..0x4]
|
||||
help: the accessed tag <TAG> later transitioned to Disabled due to a foreign write access at offsets [0x0..0x4]
|
||||
--> $DIR/illegal_write5.rs:LL:CC
|
||||
|
|
||||
LL | unsafe { *xraw = 15 };
|
||||
|
@ -5,19 +5,13 @@ LL | let _val = *xref_in_mem;
|
||||
| ^^^^^^^^^^^^ reborrow through <TAG> at ALLOC[0x0] is forbidden
|
||||
|
|
||||
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
|
||||
= help: the accessed tag <TAG> is a child of the conflicting tag <TAG>
|
||||
= help: the conflicting tag <TAG> has state Disabled which forbids this reborrow (acting as a child read access)
|
||||
help: the accessed tag <TAG> was created here
|
||||
= help: the accessed tag <TAG> has state Disabled which forbids this reborrow (acting as a child read access)
|
||||
help: the accessed tag <TAG> was created here, in the initial state Frozen
|
||||
--> $DIR/load_invalid_shr.rs:LL:CC
|
||||
|
|
||||
LL | let xref_in_mem = Box::new(xref);
|
||||
| ^^^^^^^^^^^^^^
|
||||
help: the conflicting tag <TAG> was created here, in the initial state Frozen
|
||||
--> $DIR/load_invalid_shr.rs:LL:CC
|
||||
|
|
||||
LL | let xref = unsafe { &*xraw };
|
||||
| ^^^^^^
|
||||
help: the conflicting tag <TAG> later transitioned to Disabled due to a foreign write access at offsets [0x0..0x4]
|
||||
help: the accessed tag <TAG> later transitioned to Disabled due to a foreign write access at offsets [0x0..0x4]
|
||||
--> $DIR/load_invalid_shr.rs:LL:CC
|
||||
|
|
||||
LL | unsafe { *xraw = 42 }; // unfreeze
|
||||
|
@ -5,19 +5,13 @@ LL | *LEAK = 7;
|
||||
| ^^^^^^^^^ write access through <TAG> at ALLOC[0x0] is forbidden
|
||||
|
|
||||
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
|
||||
= help: the accessed tag <TAG> is a child of the conflicting tag <TAG>
|
||||
= help: the conflicting tag <TAG> has state Disabled which forbids this child write access
|
||||
help: the accessed tag <TAG> was created here
|
||||
= help: the accessed tag <TAG> has state Disabled which forbids this child write access
|
||||
help: the accessed tag <TAG> was created here, in the initial state Frozen
|
||||
--> $DIR/mut_exclusive_violation1.rs:LL:CC
|
||||
|
|
||||
LL | fn unknown_code_1(x: &i32) {
|
||||
| ^
|
||||
help: the conflicting tag <TAG> was created here, in the initial state Frozen
|
||||
--> $DIR/mut_exclusive_violation1.rs:LL:CC
|
||||
|
|
||||
LL | unknown_code_1(&*our);
|
||||
| ^^^^^
|
||||
help: the conflicting tag <TAG> later transitioned to Disabled due to a foreign write access at offsets [0x0..0x4]
|
||||
help: the accessed tag <TAG> later transitioned to Disabled due to a foreign write access at offsets [0x0..0x4]
|
||||
--> $DIR/mut_exclusive_violation1.rs:LL:CC
|
||||
|
|
||||
LL | *our = 5;
|
||||
|
@ -5,19 +5,13 @@ LL | *raw1 = 3;
|
||||
| ^^^^^^^^^ write access through <TAG> at ALLOC[0x0] is forbidden
|
||||
|
|
||||
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
|
||||
= help: the accessed tag <TAG> is a child of the conflicting tag <TAG>
|
||||
= help: the conflicting tag <TAG> has state Disabled which forbids this child write access
|
||||
help: the accessed tag <TAG> was created here
|
||||
= help: the accessed tag <TAG> has state Disabled which forbids this child write access
|
||||
help: the accessed tag <TAG> was created here, in the initial state Reserved
|
||||
--> $DIR/mut_exclusive_violation2.rs:LL:CC
|
||||
|
|
||||
LL | let raw1 = ptr1.as_mut();
|
||||
| ^^^^^^^^^^^^^
|
||||
help: the conflicting tag <TAG> was created here, in the initial state Reserved
|
||||
--> $DIR/mut_exclusive_violation2.rs:LL:CC
|
||||
|
|
||||
LL | let raw1 = ptr1.as_mut();
|
||||
| ^^^^^^^^^^^^^
|
||||
help: the conflicting tag <TAG> later transitioned to Disabled due to a foreign write access at offsets [0x0..0x4]
|
||||
help: the accessed tag <TAG> later transitioned to Disabled due to a foreign write access at offsets [0x0..0x4]
|
||||
--> $DIR/mut_exclusive_violation2.rs:LL:CC
|
||||
|
|
||||
LL | *raw2 = 2;
|
||||
|
@ -5,19 +5,13 @@ LL | foo(some_xref);
|
||||
| ^^^^^^^^^ reborrow through <TAG> at ALLOC[0x0] is forbidden
|
||||
|
|
||||
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
|
||||
= help: the accessed tag <TAG> is a child of the conflicting tag <TAG>
|
||||
= help: the conflicting tag <TAG> has state Disabled which forbids this reborrow (acting as a child read access)
|
||||
help: the accessed tag <TAG> was created here
|
||||
= help: the accessed tag <TAG> has state Disabled which forbids this reborrow (acting as a child read access)
|
||||
help: the accessed tag <TAG> was created here, in the initial state Frozen
|
||||
--> $DIR/pass_invalid_shr_option.rs:LL:CC
|
||||
|
|
||||
LL | let some_xref = unsafe { Some(&*xraw) };
|
||||
| ^^^^^^^^^^^^
|
||||
help: the conflicting tag <TAG> was created here, in the initial state Frozen
|
||||
--> $DIR/pass_invalid_shr_option.rs:LL:CC
|
||||
|
|
||||
LL | let some_xref = unsafe { Some(&*xraw) };
|
||||
| ^^^^^^
|
||||
help: the conflicting tag <TAG> later transitioned to Disabled due to a foreign write access at offsets [0x0..0x4]
|
||||
help: the accessed tag <TAG> later transitioned to Disabled due to a foreign write access at offsets [0x0..0x4]
|
||||
--> $DIR/pass_invalid_shr_option.rs:LL:CC
|
||||
|
|
||||
LL | unsafe { *xraw = 42 }; // unfreeze
|
||||
|
@ -5,19 +5,13 @@ LL | foo(pair_xref);
|
||||
| ^^^^^^^^^ reborrow through <TAG> at ALLOC[0x0] is forbidden
|
||||
|
|
||||
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
|
||||
= help: the accessed tag <TAG> is a child of the conflicting tag <TAG>
|
||||
= help: the conflicting tag <TAG> has state Disabled which forbids this reborrow (acting as a child read access)
|
||||
help: the accessed tag <TAG> was created here
|
||||
= help: the accessed tag <TAG> has state Disabled which forbids this reborrow (acting as a child read access)
|
||||
help: the accessed tag <TAG> was created here, in the initial state Frozen
|
||||
--> $DIR/pass_invalid_shr_tuple.rs:LL:CC
|
||||
|
|
||||
LL | let pair_xref = unsafe { (&*xraw0, &*xraw1) };
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
help: the conflicting tag <TAG> was created here, in the initial state Frozen
|
||||
--> $DIR/pass_invalid_shr_tuple.rs:LL:CC
|
||||
|
|
||||
LL | let pair_xref = unsafe { (&*xraw0, &*xraw1) };
|
||||
| ^^^^^^^
|
||||
help: the conflicting tag <TAG> later transitioned to Disabled due to a foreign write access at offsets [0x0..0x4]
|
||||
help: the accessed tag <TAG> later transitioned to Disabled due to a foreign write access at offsets [0x0..0x4]
|
||||
--> $DIR/pass_invalid_shr_tuple.rs:LL:CC
|
||||
|
|
||||
LL | unsafe { *xraw0 = 42 }; // unfreeze
|
||||
|
@ -5,19 +5,13 @@ LL | ret
|
||||
| ^^^ reborrow through <TAG> at ALLOC[0x4] is forbidden
|
||||
|
|
||||
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
|
||||
= help: the accessed tag <TAG> is a child of the conflicting tag <TAG>
|
||||
= help: the conflicting tag <TAG> has state Disabled which forbids this reborrow (acting as a child read access)
|
||||
help: the accessed tag <TAG> was created here
|
||||
= help: the accessed tag <TAG> has state Disabled which forbids this reborrow (acting as a child read access)
|
||||
help: the accessed tag <TAG> was created here, in the initial state Frozen
|
||||
--> $DIR/return_invalid_shr_option.rs:LL:CC
|
||||
|
|
||||
LL | let ret = Some(unsafe { &(*xraw).1 });
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: the conflicting tag <TAG> was created here, in the initial state Frozen
|
||||
--> $DIR/return_invalid_shr_option.rs:LL:CC
|
||||
|
|
||||
LL | let ret = Some(unsafe { &(*xraw).1 });
|
||||
| ^^^^^^^^^^
|
||||
help: the conflicting tag <TAG> later transitioned to Disabled due to a foreign write access at offsets [0x0..0x8]
|
||||
help: the accessed tag <TAG> later transitioned to Disabled due to a foreign write access at offsets [0x0..0x8]
|
||||
--> $DIR/return_invalid_shr_option.rs:LL:CC
|
||||
|
|
||||
LL | unsafe { *xraw = (42, 23) }; // unfreeze
|
||||
|
@ -5,19 +5,13 @@ LL | ret
|
||||
| ^^^ reborrow through <TAG> at ALLOC[0x4] is forbidden
|
||||
|
|
||||
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
|
||||
= help: the accessed tag <TAG> is a child of the conflicting tag <TAG>
|
||||
= help: the conflicting tag <TAG> has state Disabled which forbids this reborrow (acting as a child read access)
|
||||
help: the accessed tag <TAG> was created here
|
||||
= help: the accessed tag <TAG> has state Disabled which forbids this reborrow (acting as a child read access)
|
||||
help: the accessed tag <TAG> was created here, in the initial state Frozen
|
||||
--> $DIR/return_invalid_shr_tuple.rs:LL:CC
|
||||
|
|
||||
LL | let ret = (unsafe { &(*xraw).1 },);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: the conflicting tag <TAG> was created here, in the initial state Frozen
|
||||
--> $DIR/return_invalid_shr_tuple.rs:LL:CC
|
||||
|
|
||||
LL | let ret = (unsafe { &(*xraw).1 },);
|
||||
| ^^^^^^^^^^
|
||||
help: the conflicting tag <TAG> later transitioned to Disabled due to a foreign write access at offsets [0x0..0x8]
|
||||
help: the accessed tag <TAG> later transitioned to Disabled due to a foreign write access at offsets [0x0..0x8]
|
||||
--> $DIR/return_invalid_shr_tuple.rs:LL:CC
|
||||
|
|
||||
LL | unsafe { *xraw = (42, 23) }; // unfreeze
|
||||
|
@ -5,18 +5,12 @@ LL | *(x as *const i32 as *mut i32) = 7;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ write access through <TAG> at ALLOC[0x0] is forbidden
|
||||
|
|
||||
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
|
||||
= help: the accessed tag <TAG> is a child of the conflicting tag <TAG>
|
||||
= help: the conflicting tag <TAG> has state Frozen which forbids this child write access
|
||||
help: the accessed tag <TAG> was created here
|
||||
= help: the accessed tag <TAG> has state Frozen which forbids this child write access
|
||||
help: the accessed tag <TAG> was created here, in the initial state Frozen
|
||||
--> $DIR/shr_frozen_violation1.rs:LL:CC
|
||||
|
|
||||
LL | fn unknown_code(x: &i32) {
|
||||
| ^
|
||||
help: the conflicting tag <TAG> was created here, in the initial state Frozen
|
||||
--> $DIR/shr_frozen_violation1.rs:LL:CC
|
||||
|
|
||||
LL | unknown_code(&*x);
|
||||
| ^^^
|
||||
= note: BACKTRACE (of the first span):
|
||||
= note: inside `unknown_code` at $DIR/shr_frozen_violation1.rs:LL:CC
|
||||
note: inside `foo`
|
||||
|
@ -5,25 +5,19 @@ LL | *y += 1; // Failure
|
||||
| ^^^^^^^ write access through <TAG> at ALLOC[0x0] is forbidden
|
||||
|
|
||||
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
|
||||
= help: the accessed tag <TAG> is a child of the conflicting tag <TAG>
|
||||
= help: the conflicting tag <TAG> has state Frozen which forbids this child write access
|
||||
help: the accessed tag <TAG> was created here
|
||||
= help: the accessed tag <TAG> has state Frozen which forbids this child write access
|
||||
help: the accessed tag <TAG> was created here, in the initial state Reserved
|
||||
--> $DIR/alternate-read-write.rs:LL:CC
|
||||
|
|
||||
LL | let y = unsafe { &mut *(x as *mut u8) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
help: the conflicting tag <TAG> was created here, in the initial state Reserved
|
||||
--> $DIR/alternate-read-write.rs:LL:CC
|
||||
|
|
||||
LL | let y = unsafe { &mut *(x as *mut u8) };
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
help: the conflicting tag <TAG> later transitioned to Active due to a child write access at offsets [0x0..0x1]
|
||||
help: the accessed tag <TAG> later transitioned to Active due to a child write access at offsets [0x0..0x1]
|
||||
--> $DIR/alternate-read-write.rs:LL:CC
|
||||
|
|
||||
LL | *y += 1; // Success
|
||||
| ^^^^^^^
|
||||
= help: this transition corresponds to the first write to a 2-phase borrowed mutable reference
|
||||
help: the conflicting tag <TAG> later transitioned to Frozen due to a foreign read access at offsets [0x0..0x1]
|
||||
help: the accessed tag <TAG> later transitioned to Frozen due to a foreign read access at offsets [0x0..0x1]
|
||||
--> $DIR/alternate-read-write.rs:LL:CC
|
||||
|
|
||||
LL | let _val = *x;
|
||||
|
@ -5,19 +5,13 @@ LL | child2.write(2);
|
||||
| ^^^^^^^^^^^^^^^ write access through <TAG> at ALLOC[0x0] is forbidden
|
||||
|
|
||||
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
|
||||
= help: the accessed tag <TAG> is a child of the conflicting tag <TAG>
|
||||
= help: the conflicting tag <TAG> has state Disabled which forbids this child write access
|
||||
help: the accessed tag <TAG> was created here
|
||||
= help: the accessed tag <TAG> has state Disabled which forbids this child write access
|
||||
help: the accessed tag <TAG> was created here, in the initial state Reserved
|
||||
--> $DIR/children-can-alias.rs:LL:CC
|
||||
|
|
||||
LL | let child2 = x.as_ptr();
|
||||
| ^^^^^^^^^^
|
||||
help: the conflicting tag <TAG> was created here, in the initial state Reserved
|
||||
--> $DIR/children-can-alias.rs:LL:CC
|
||||
|
|
||||
LL | let child2 = x.as_ptr();
|
||||
| ^
|
||||
help: the conflicting tag <TAG> later transitioned to Disabled due to a foreign write access at offsets [0x0..0x1]
|
||||
help: the accessed tag <TAG> later transitioned to Disabled due to a foreign write access at offsets [0x0..0x1]
|
||||
--> $DIR/children-can-alias.rs:LL:CC
|
||||
|
|
||||
LL | child1.write(1);
|
||||
|
@ -5,19 +5,13 @@ LL | rmut[5] += 1;
|
||||
| ^^^^^^^^^^^^ read access through <TAG> at ALLOC[0x5] is forbidden
|
||||
|
|
||||
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
|
||||
= help: the accessed tag <TAG> is a child of the conflicting tag <TAG>
|
||||
= help: the conflicting tag <TAG> has state Disabled which forbids this child read access
|
||||
help: the accessed tag <TAG> was created here
|
||||
= help: the accessed tag <TAG> has state Disabled which forbids this child read access
|
||||
help: the accessed tag <TAG> was created here, in the initial state Reserved
|
||||
--> $DIR/error-range.rs:LL:CC
|
||||
|
|
||||
LL | let rmut = &mut *addr_of_mut!(data[0..6]);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
help: the conflicting tag <TAG> was created here, in the initial state Reserved
|
||||
--> $DIR/error-range.rs:LL:CC
|
||||
|
|
||||
LL | let rmut = &mut *addr_of_mut!(data[0..6]);
|
||||
| ^^^^
|
||||
help: the conflicting tag <TAG> later transitioned to Disabled due to a foreign write access at offsets [0x5..0x6]
|
||||
help: the accessed tag <TAG> later transitioned to Disabled due to a foreign write access at offsets [0x5..0x6]
|
||||
--> $DIR/error-range.rs:LL:CC
|
||||
|
|
||||
LL | data[5] = 1;
|
||||
|
@ -1,14 +1,15 @@
|
||||
//@compile-flags: -Zmiri-tree-borrows
|
||||
//@error-in-other-file: /deallocation through .* is forbidden/
|
||||
|
||||
fn inner(x: &mut i32, f: fn(&mut i32)) {
|
||||
fn inner(x: &mut i32, f: fn(*mut i32)) {
|
||||
// `f` may mutate, but it may not deallocate!
|
||||
// `f` takes a raw pointer so that the only protector
|
||||
// is that on `x`
|
||||
f(x)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
inner(Box::leak(Box::new(0)), |x| {
|
||||
let raw = x as *mut _;
|
||||
inner(Box::leak(Box::new(0)), |raw| {
|
||||
drop(unsafe { Box::from_raw(raw) });
|
||||
});
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ LL | drop(unsafe { Box::from_raw(raw) });
|
||||
help: the strongly protected tag <TAG> was created here, in the initial state Reserved
|
||||
--> $DIR/strongly-protected.rs:LL:CC
|
||||
|
|
||||
LL | fn inner(x: &mut i32, f: fn(&mut i32)) {
|
||||
LL | fn inner(x: &mut i32, f: fn(*mut i32)) {
|
||||
| ^
|
||||
= note: BACKTRACE (of the first span):
|
||||
= note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC
|
||||
@ -28,7 +28,7 @@ note: inside closure
|
||||
|
|
||||
LL | drop(unsafe { Box::from_raw(raw) });
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: inside `<{closure@$DIR/strongly-protected.rs:LL:CC} as std::ops::FnOnce<(&mut i32,)>>::call_once - shim` at RUSTLIB/core/src/ops/function.rs:LL:CC
|
||||
= note: inside `<{closure@$DIR/strongly-protected.rs:LL:CC} as std::ops::FnOnce<(*mut i32,)>>::call_once - shim` at RUSTLIB/core/src/ops/function.rs:LL:CC
|
||||
note: inside `inner`
|
||||
--> $DIR/strongly-protected.rs:LL:CC
|
||||
|
|
||||
@ -37,8 +37,7 @@ LL | f(x)
|
||||
note: inside `main`
|
||||
--> $DIR/strongly-protected.rs:LL:CC
|
||||
|
|
||||
LL | / inner(Box::leak(Box::new(0)), |x| {
|
||||
LL | | let raw = x as *mut _;
|
||||
LL | / inner(Box::leak(Box::new(0)), |raw| {
|
||||
LL | | drop(unsafe { Box::from_raw(raw) });
|
||||
LL | | });
|
||||
| |______^
|
||||
|
Loading…
Reference in New Issue
Block a user