Skip to content

Conversation

@royAmmerschuber
Copy link
Contributor

If there is no exposed node on the main subtree that allows a child write, then a wildcard access to the tree is invalid.
This wasn't caught before if there were multiple exposed nodes in the main subtree whose tag was larger than the accessed tag.

@rustbot
Copy link
Collaborator

rustbot commented Dec 10, 2025

Thank you for contributing to Miri! A reviewer will take a look at your PR, typically within a week or two.
Please remember to not force-push to the PR branch except when you need to rebase due to a conflict or when the reviewer asks you for it.

@rustbot rustbot added the S-waiting-on-review Status: Waiting for a review to complete label Dec 10, 2025
Copy link
Member

@RalfJung RalfJung left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! I can follow the logic. However, is there any way to generalize this so it doesn't just work for the main tree? Currently it looks like a pretty ad-hoc special case, and there are probably many of those that we could add.

I'm also confused by the PR title. This is about whether there's any eligible exposed node on the main tree, right? Why do you talk about "multiple"?

This wasn't caught before if there were multiple exposed nodes in the main subtree whose tag was larger than the accessed tag.

Are you saying this was caught if there was exactly one exposed node in the main subtree whose tag was larger than the accessed tag? How?

View changes since this review

if node.is_exposed
&& perm.permission.strongest_allowed_child_access(protected)
>= access_kind.into()
&& max_local_tag.is_none_or(|max_local_tag| max_local_tag > node.tag)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
&& max_local_tag.is_none_or(|max_local_tag| max_local_tag > node.tag)
&& max_local_tag.is_none_or(|max_local_tag| max_local_tag >= node.tag)

The max-local-tag itself can be the souce of local accesses, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

max_local_tag is actually never equal to node.tag as we only call perform_wildcard_access on the trees which don't contain max_local_tag. But >= is more fitting for the name of max_local_tag so ill change this.

Comment on lines +1133 to +1139
// Check that this is the main subtree.
&& self
.wildcard_accesses
.get(root)
.unwrap()
.access_relatedness(access_kind, true)
.is_none()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does this check that it is the main tree...?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This checks if no foreign access is possible on the root of the subtree. Only the main subtree doesn't allow foreign accesses, so if access_relatedness() is None then root is the main root.
I should add a comment to the bool flag (/* only_foreign */). Or I could make max_foreign_access public and read that directly.

This way it's implemented technically makes it generic to all subtrees, But the only one it actually effects is the main subtree.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The main problem here is that comment ant code don't match. Given that code, the comment should explain why this is correct for any tree that does not allow foreign accesses at the root.

Read,
Write,
}
impl From<AccessKind> for WildcardAccessLevel {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we have to start converting between them, there's not really any point any more in them being different types.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could replace WildcardAccessLevel with Option<AccessKind>. We would have to implement Ord for AccessKind and rely on Option's Ord implementation, but I think that would still be the correct logic.

I do think it makes sense to keep the types separate since they represent different things. Access kind is the type of a concrete access, while access level represents the highest allowed access that is possible.

I only use this implementation to check if an access kind is allowed under a specific access level. Maybe I should replace this with a method access_level.allows(access_kind).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I only use this implementation to check if an access kind is allowed under a specific access level. Maybe I should replace this with a method access_level.allows(access_kind).

That would also be reasonable.


// We only count exposed nodes through which an access could happen.
if node.is_exposed
&& perm.permission.strongest_allowed_child_access(protected)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably rename that method to include wildcard; it's currently confusing when one reads this code and tries to understand it without knowing exactly by heart what each function does.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I forgot to rename this function to strongest_allowed_local_access which would be the correct term. I think the function name (at least with this change) already tells you exactly what the function does.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, I see... but then it is somewhat confusing that it returns a WildcardAccess.

@RalfJung RalfJung added S-waiting-on-author Status: Waiting for the PR author to address review comments and removed S-waiting-on-review Status: Waiting for a review to complete labels Dec 13, 2025
@royAmmerschuber
Copy link
Contributor Author

However, is there any way to generalize this so it doesn't just work for the main tree? Currently it looks like a pretty ad-hoc special case, and there are probably many of those that we could add.

This PR is trying to better approximate the ideal version of the algorithm (where we recalculate the wildcard data structure before each access).
It should now return a no_valid_exposed_references_error() in the same cases as the ideal algorithm. It doesn't cover the cases where a TransitionError would get returned, but for these there is no easy way to check them, so we would probably have to implement the ideal algorithm directly.

As for this only being implemented for the main subtree. This error already never gets raised on the other subtrees. An access is UB if there exist no valid exposed nodes on the main subtree, even if there are valid exposed nodes on other subtrees. This is because those other subtrees would also have to be attached to one of the valid exposed nodes on the main subtree.

I'm also confused by the PR title. This is about whether there's any eligible exposed node on the main tree, right? Why do you talk about "multiple"?

Are you saying this was caught if there was exactly one exposed node in the main subtree whose tag was larger than the accessed tag? How?

Yes, it's already handled for the single invalid exposed case (see test case cross_tree_update_main_invalid_exposed.rs). In the single case when we try to calculate the relatedness for the invalid exposed node we know that neither a local (because it's invalid) nor a foreign (because it's the only exposed node on the main subtree) access could happen so its UB.
However, if this node has an invalid exposed cousin, then it thinks a foreign access could have happened from that cousin.

@RalfJung
Copy link
Member

RalfJung commented Dec 15, 2025

This PR is trying to better approximate the ideal version of the algorithm (where we recalculate the wildcard data structure before each access).
It should now return a no_valid_exposed_references_error() in the same cases as the ideal algorithm.

I like that way of framing it, thanks. However, I would say the ideal (or rather, idealized) algorithm would just not have the data structure at all and do nested tree traversals.

This should be reflected in the comments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-author Status: Waiting for the PR author to address review comments

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants