-
Notifications
You must be signed in to change notification settings - Fork 417
Tree Borrows: multiple invalid exposed nodes on main subtree #4757
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Tree Borrows: multiple invalid exposed nodes on main subtree #4757
Conversation
|
Thank you for contributing to Miri! A reviewer will take a look at your PR, typically within a week or two. |
There was a problem hiding this 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?
| 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) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| && 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?
There was a problem hiding this comment.
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.
| // Check that this is the main subtree. | ||
| && self | ||
| .wildcard_accesses | ||
| .get(root) | ||
| .unwrap() | ||
| .access_relatedness(access_kind, true) | ||
| .is_none() |
There was a problem hiding this comment.
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...?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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).
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
This PR is trying to better approximate the ideal version of the algorithm (where we recalculate the wildcard data structure before each access). 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.
Yes, it's already handled for the single invalid exposed case (see test case |
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. |
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.