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

RFC for Rust UB checks #3092

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

celinval
Copy link
Contributor

@celinval celinval commented Mar 18, 2024

Create a new RFC for standardizing Kani's UB checks.

I left the "Software Design" section empty for now so we can first focus on the user experience.

Note that this RFC might need some adjustment depending on the outcome of diffblue/cbmc#8242 and diffblue/cbmc#8226.

Related to #3089

Rendered version: https://celinval.github.io/kani-dev/rfc/rfcs/0010-rust-ub-checks.html

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses.

@celinval celinval requested a review from a team as a code owner March 18, 2024 23:21
rfc/src/rfcs/0010-rust-ub-checks.md Outdated Show resolved Hide resolved
rfc/src/rfcs/0010-rust-ub-checks.md Outdated Show resolved Hide resolved

A counter example that triggers UB may require extra tooling for debugging, e.g.: MIRI or valgrind.
We propose that tests added by concrete playback in those cases should include a comment stating such limitation.
Other possibilities are discussed in [0010-rust-ub-checks.md#open-questions].
Copy link
Contributor

Choose a reason for hiding this comment

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

Same here for link.

rfc/src/rfcs/0010-rust-ub-checks.md Outdated Show resolved Hide resolved
rfc/src/rfcs/0010-rust-ub-checks.md Outdated Show resolved Hide resolved
rfc/src/rfcs/0010-rust-ub-checks.md Outdated Show resolved Hide resolved
rfc/src/rfcs/0010-rust-ub-checks.md Outdated Show resolved Hide resolved
rfc/src/rfcs/0010-rust-ub-checks.md Outdated Show resolved Hide resolved
The default behavior matches the one that we believe is the recommended for most users due to soundness.
In some cases, users may need to disable some checks for reasons such as spurious CEX or proof scalability.
Thus, we suggest that every category of checks should have an opt-out mechanism that can either be global or local;
i.e.: via command argument or harness attribute.
Copy link
Contributor

Choose a reason for hiding this comment

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

Since some of our checks are over-approximating, we may also need to introduce code-level control at some point, e.g. to enable/disable the checks for a few lines of code.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Indeed. It might be hard for dependencies though.

Copy link
Contributor

Choose a reason for hiding this comment

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

+1

Copy link
Contributor Author

@celinval celinval Jun 28, 2024

Choose a reason for hiding this comment

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

Is it OK if I leave this as open question?

Copy link
Contributor

@adpaco-aws adpaco-aws left a comment

Choose a reason for hiding this comment

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

Thanks, @celinval ! I'm all down for a more consistent and intuitive experience like the one proposed in this RFC.

However, I'd have liked to see some content regarding categorization of UB checks. At the same time, I acknowledge that this subject deserves its own RFC, so I'd be satisfied if this RFC included a forward declaration about a future categorization effort that tries to be as exhaustive as possible (think of it as a more detailed version of this reference section).

rfc/src/rfcs/0010-rust-ub-checks.md Outdated Show resolved Hide resolved
detected undefined behavior.

For simplicity, we propose that all undefined behavior checks are modelled as assert-assume pairs.
We propose that the status of all passing assertions that may be affected by this check to be displayed as
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe it'll become clearer to me later, but this sentence seems quite ambiguous to me. Does "may be affected" here mean "goes after"?

Also have some concerns about this UX point, but let me read till the end and will come back later.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yep, I don't think this became clearer to me after reviewing the rest of the RFC. Why only passing assertions? Don't you want to refer to any checks in general, also regardless of their status?

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 believe we have two sound options here:

  1. Change the status of ALL passing assertions as undetermined.
  2. Change the status of passing assertions only if they are downstream from the UB check that has failed. I.e., do something similar to what is being proposed in the Fatal Assertions PR (introduce 'fatal assertions' diffblue/cbmc#8226). In this case, you are traversing the control flow graph to rule out assertions that can only occur before the UB check.

I did leave this slightly ambiguous on purpose. Both options above are an over-approximation of the set of assertions that could be reached after the UB. The option 2 is an optimization of option 1, and I'm curious on how function pointers and other things will play out here.

In my opinion, they are both acceptable (as long as they are sound) and better than what we have today. I am not convinced the optimization adds a lot of value, since users shouldn't really be using partial results from a program with UB.

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 tried to make it more explicit. Let me know if that makes sense now.

rfc/src/rfcs/0010-rust-ub-checks.md Outdated Show resolved Hide resolved
fn buggy_code() {
let mut value: bool = false;
unsafe {
let ptr: *mut u8 = &mut value as *mut _ as *mut u8;
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is the double as * mut <type> needed here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Because we first need to cast the reference to a raw pointer, then we need to cast to a u8 pointer.

able to detect efficiently. For example, we could fail if casting between types that have different value
requirements, i.e.: fail in the cast `*mut bool as *mut u8`.

For option 2, Kani may fail verification even if the code does not have UB.
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't like this option because I think it'll reduce Kani's usability in such cases. The unsafe code is likely to stay as it is, forcing users to introduce verification-specific code that may or may not be equivalent to the code not triggering UB in the first place.

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 agree that this is not ideal, but the ideal solution may not scale to basic examples.

In cases where option 1 is not feasible, or not yet implemented, option 2 may enable us to verify most existing code out there and fail for very specific use cases.

For example, we won't likely be able to implement a full stacked borrows in Kani since the runtime overhead can be overwhelming. In that case, modeling an over-abstraction may allow us to reason about aliasing violation in most use cases, but we may need to reject some code that is accepted by Miri.

I would be OK with that, as long as the failure explicitly mentions that this may be due to an over-approximation. Users would still be able to run the counter-example in Miri to check if it is spurious or not. Maybe we can even eventually integrate with Miri to check that.

rfc/src/rfcs/0010-rust-ub-checks.md Outdated Show resolved Hide resolved
rfc/src/rfcs/0010-rust-ub-checks.md Outdated Show resolved Hide resolved
The default behavior matches the one that we believe is the recommended for most users due to soundness.
In some cases, users may need to disable some checks for reasons such as spurious CEX or proof scalability.
Thus, we suggest that every category of checks should have an opt-out mechanism that can either be global or local;
i.e.: via command argument or harness attribute.
Copy link
Contributor

Choose a reason for hiding this comment

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

+1

rfc/src/rfcs/0010-rust-ub-checks.md Outdated Show resolved Hide resolved
rfc/src/rfcs/0010-rust-ub-checks.md Outdated Show resolved Hide resolved
- **Feature Name:** Rust UB Checks (`rust-ub-checks`)
- **Feature Request Issue:** [#3089](https://github.com/model-checking/kani/issues/3089)
- **RFC PR:** [#XXXX](https://github.com/model-checking/kani/pull/3091)
- **Status:** Under Review
Copy link
Member

Choose a reason for hiding this comment

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

Nit pick: I suppose the above need to be updated?!

tautschnig pushed a commit that referenced this pull request Apr 5, 2024
In the previous PR #3085, we did not support checks for `write_bytes`
which is added in this PR.

I am waiting for #3092 to add expected tests.
zpzigi754 pushed a commit to zpzigi754/kani that referenced this pull request May 8, 2024
In the previous PR model-checking#3085, we did not support checks for `write_bytes`
which is added in this PR.

I am waiting for model-checking#3092 to add expected tests.
@feliperodri feliperodri added the T-RFC Label RFC PRs and Issues label Jun 11, 2024
  - Changed the example.
  - Improved text.
  - Removed restriction on unstable opt-out.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
T-RFC Label RFC PRs and Issues
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants