Skip to content
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

analyze: allow overriding dataflow for specific permissions #1088

Merged
merged 4 commits into from
May 2, 2024

Conversation

spernsteiner
Copy link
Collaborator

This adds a new internal feature for overriding dataflow analysis for specific permissions of specific pointers. The propagate method of dataflow now takes an additional updates_forbidden set, which has a PermissionSet mask for every PointerId, and avoids adding or removing a permission for a ptr if the corresponding bit is set in updates_forbidden[ptr]. When updates_forbidden is used, the resulting permissions after running dataflow might not actually satisfy the dataflow constraints.

This is designed to support the PDG "NON_NULL override" feature, where information about nullability from the PDG can override static analysis results, though that feature is not part of the current PR.

@spernsteiner spernsteiner force-pushed the analyze-dataflow-readonly branch from 8851c89 to 9f3129d Compare May 2, 2024 17:05
@spernsteiner spernsteiner merged commit 9511a4f into master May 2, 2024
9 checks passed
spernsteiner added a commit that referenced this pull request Jun 25, 2024
This branch implements rewriting of nullable pointers (those lacking
`PermissionSet::NON_NULL`) to `Option`. This includes the following
kinds of rewrites:

* Type annotations: `Option<&mut T>` instead of `&mut T`
* Casts between nullable and non-nullable via `p.unwrap()` and
`Some(p)`. For most permissions, we implement only one direction because
the other is invalid/nonsensical, but here we implement both in order to
support "unsound" rewrites involving overridden `NON_NULL` flags (as in
#1088).
* Borrows: when casting `p: Option<&mut T>`, we use
`p.as_deref_mut().unwrap()` instead of `p.unwrap()` to avoid consuming
the original `p`. (In the code, this is called a "downgrade", since it
allows borrowing `Option<Box<T>>` as `Option<&T>` and similar.)
* Pointer projections on nullable pointers. Where `NON_NULL` pointers
would use `&p[0]`, nullable ones use `p.map(|ptr| &ptr[0])`. Internally,
this is represented similar to `Some(&p.unwrap()[0])`, but it's handled
specially by `rewrite::expr::convert` to produce a `map` call instead,
which passes through `None` without a panic.
* `unwrap()` calls on derefs. `*p` is rewritten to `*p.unwrap()`, or to
`*p.as_deref().unwrap()` if a downgrade/borrow is necessary to avoid
moving `p`.
* `ptr::null()` and `0 as *const _` to `None`, and `p.is_null()` to
`p.is_none()`.

The new `non_null_rewrites.rs` test case passes, and the rewritten code
compiles.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants