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

Closed
wants to merge 4 commits into 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
rfc/src/rfcs/0010-rust-ub-checks.md Outdated Show resolved Hide resolved
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
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
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
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
celinval added 2 commits June 28, 2024 14:49
  - Changed the example.
  - Improved text.
  - Removed restriction on unstable opt-out.
@celinval celinval force-pushed the issue-2998-ub-rfc branch from 4f6c75f to 96f50da Compare June 28, 2024 23:08

## User Experience

A UB check should behave consistently independent on how and where it is implemented.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
A UB check should behave consistently independent on how and where it is implemented.
A UB check should behave consistently independent of how and where it is implemented.

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
`UNDETERMINED` if one or more UB checks fail.
For simplicity, Kani currently over-approximate this set by marking all passing assertions as `UNDETERMINED`.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
For simplicity, Kani currently over-approximate this set by marking all passing assertions as `UNDETERMINED`.
For simplicity, Kani currently over-approximates this set by marking all passing assertions as `UNDETERMINED`.

assignment to its tracker that violates the assertion.
Picking an assignment that fails can be seen as choosing the worst possible action, known as demonic nondeterminism.

See [Open questions section](0010-rust-ub-checks.md#open-questions) for alternatives to be considered.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
See [Open questions section](0010-rust-ub-checks.md#open-questions) for alternatives to be considered.
See the [Open questions section](0014-rust-ub-checks.md#open-questions) for alternatives to be considered.


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.

Suggested change
Other possibilities are discussed in [0010-rust-ub-checks.md#open-questions].
Other possibilities are discussed in [0014-rust-ub-checks.md#open-questions].

For option 2, Kani may fail verification even if the code does not have UB.
In those cases, Kani check must be explicit about this failure being an over-approximation.
For that, we propose that the check message is clear about this limitation, and potentially its status
(see [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.

Suggested change
(see [0010-rust-ub-checks.md#open-questions]).
(see [0014-rust-ub-checks.md#open-questions]).


```rust
#[kani::proof]
#[kani::ignore(CHECK_NAMES)]
Copy link
Contributor

Choose a reason for hiding this comment

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

"ignore" is a bit too general. Maybe use ignore_ub?

Copy link
Contributor

Choose a reason for hiding this comment

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

+1


## Rationale and alternatives

Kani already has undefined behavior checks, some are implemented on the CBMC side, such as access out bounds, and
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
Kani already has undefined behavior checks, some are implemented on the CBMC side, such as access out bounds, and
Kani already has undefined behavior checks, some are implemented on the CBMC side, such as out-of-bounds access, and

```

We would like to keep taking advantage of existing instrumentation to maximize the UB check coverage.
The mechanism used to build the check, however, shouldn't influence in the user experience.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
The mechanism used to build the check, however, shouldn't influence in the user experience.
The mechanism used to build the check, however, shouldn't influence the user experience.

Copy link
Contributor

Choose a reason for hiding this comment

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

This section does a great job of explaining the current division of UB checks and how those manifest in different experiences for users, but I'm missing a call to action--what are you proposing we do about it? Should we add a model of get_unchecked to Kani so that we can catch this error ourselves and provide a better error message? Or not, because then we're not relying on existing instrumentation? We don't need to land on a precise answer now (I know the implementation section is empty), but can we give some options at least?
Also, I'm a bit confused about the scope of this RFC. The User Experience section made me think that we were just talking about whether a passing check should pass or be undetermined based on a failing UB check before it. Now it seems like we're also considering the UX of the UB checks themselves. I would recommend adding a sentence or two about consistent messaging for failing UB checks to the User Experience section if you intend for that to be part of the "consistent framework" you're proposing.

- Another possibility would be to add a `unreachable!()` statement at the end of the test case with a message
explaining why the statement should be unreachable.
- Should we deprecate the `--no-default-checks` and all `--[CHECK-NAME]-checks` checks.
- Should we add an attribute that allows us to opt-out some UB checks for a function or some code block?
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
- Should we add an attribute that allows us to opt-out some UB checks for a function or some code block?
- Should we add an attribute that allows us to opt-out of some UB checks for a function or some code block?

@zhassan-aws
Copy link
Contributor

Please take a look at the modifications suggested in the previous round of review as well.

Copy link
Contributor

@carolynzech carolynzech left a comment

Choose a reason for hiding this comment

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

Thanks! High-level comment: I think the RFC would benefit from a longer summary that outlines the key elements of what defines a "consistent framework." Bullet points are fine--something like:

  • Consistent standards for the status of assertions downstream of a failing UB check
  • Consistent error message style for failing UB checks, regardless of whether the UB was detected in Kani, CBMC, or the Rust standard library
  • Consistent mechanisms by which a user can opt in or out of a given UB check

Laying this out in the beginning would give the reader a better idea of what they can expect from reading the rest of the RFC.

The detection of an undefined behavior should impact the status of any assertion that may be reachable from the
detected undefined behavior.

For simplicity, we propose that all undefined behavior checks are modelled as assert-assume pairs.
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this comment affect the validity of this approach at all?
(More generally, the PR description mentions that those two CBMC issues will affect the RFC. Since those issues are now closed/merged, could you update the PR description to instead explain how they affect the approach outlined here, if at all?)

Copy link
Contributor

Choose a reason for hiding this comment

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

Ok, after finishing the RFC, I believe the demonic nondeterminism mention later addresses the soundness concerns from the linked comment.

Comment on lines +26 to +28
We propose that the status of all passing assertions that may be affected by this check to be displayed as
`UNDETERMINED` if one or more UB checks fail.
For simplicity, Kani currently over-approximate this set by marking all passing assertions as `UNDETERMINED`.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
We propose that the status of all passing assertions that may be affected by this check to be displayed as
`UNDETERMINED` if one or more UB checks fail.
For simplicity, Kani currently over-approximate this set by marking all passing assertions as `UNDETERMINED`.
Currently, if a UB check fails, Kani overapproximates and marks all passing assertions as `UNDETERMINED`.
We propose refining this overapproximation to only mark a passing assertion as `UNDETERMINED` if it is reachable from the failing UB check.

Copy link
Contributor

Choose a reason for hiding this comment

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

I suppose after looking at this comment, maybe "reachable" isn't the right word here--you said "downstream," and I take the difference to be that "downstream" just means "after" whereas "reachable" is "after, and also reachable." So perhaps this section can say that we propose an assertion be undetermined if it's "downstream" of the failing UB check, and then later, as an example of future pruning, you could give the example of only reachable passing assertions being undetermined.

Copy link
Contributor

Choose a reason for hiding this comment

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

My overall motivation here is to try to be specific about what exactly we're proposing--we can always come back and update the RFC if we implement something different.

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 actually don't want to be super specific at this point. Maybe let me change the proposal to say that we shall mark all passing assertions as UNDETERMINED, and mentioned that refining the set of assertions marked as UNDETERMINED is out of scope of this RFC.

We propose that the status of all passing assertions that may be affected by this check to be displayed as
`UNDETERMINED` if one or more UB checks fail.
For simplicity, Kani currently over-approximate this set by marking all passing assertions as `UNDETERMINED`.
Future pruning of this set can be done with further analysis, but it should not affect soundness.
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you give examples of other pruning that we could do / it would make sense for us to do?

Comment on lines +32 to +33
This may create spurious counter examples for cases where the failing UB check is implemented using "demonic"
non-determinism.[^demonic]
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you explain why?

### Concrete playback of UB checks

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.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
We propose that tests added by concrete playback in those cases should include a comment stating such limitation.
We propose that tests added by concrete playback in those cases should include a comment stating this limitation.


```rust
#[kani::proof]
#[kani::ignore(CHECK_NAMES)]
Copy link
Contributor

Choose a reason for hiding this comment

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

+1

Comment on lines +153 to +157
Failing due to an assumption check inside `get_unchecked` function.

```plaintext
Failed Checks: assumption failed
```
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
Failing due to an assumption check inside `get_unchecked` function.
```plaintext
Failed Checks: assumption failed
```
Failing due to an [assumption check](https://github.com/rust-lang/rust/blob/a1d7676d6a8c6ff13f9165e98cc25eeec66cb592/library/core/src/slice/index.rs#L255) inside the `get_unchecked` function.
```plaintext
Failed Checks: assumption failed
File: "library/core/src/slice/index.rs", line 255, in <usize as std::slice::SliceIndex<[i32]>>::get_unchecked

Copy link
Contributor

Choose a reason for hiding this comment

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

(Just to make it a bit clearer that this is an assumption in the standard library itself, not some Kani model of get_unchecked).

```

We would like to keep taking advantage of existing instrumentation to maximize the UB check coverage.
The mechanism used to build the check, however, shouldn't influence in the user experience.
Copy link
Contributor

Choose a reason for hiding this comment

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

This section does a great job of explaining the current division of UB checks and how those manifest in different experiences for users, but I'm missing a call to action--what are you proposing we do about it? Should we add a model of get_unchecked to Kani so that we can catch this error ourselves and provide a better error message? Or not, because then we're not relying on existing instrumentation? We don't need to land on a precise answer now (I know the implementation section is empty), but can we give some options at least?
Also, I'm a bit confused about the scope of this RFC. The User Experience section made me think that we were just talking about whether a passing check should pass or be undetermined based on a failing UB check before it. Now it seems like we're also considering the UX of the UB checks themselves. I would recommend adding a sentence or two about consistent messaging for failing UB checks to the User Experience section if you intend for that to be part of the "consistent framework" you're proposing.

@celinval
Copy link
Contributor Author

@zhassan-aws @carolynzech thank you for the latest round of review.

I gave this PR a second thought, and I decided to close it. Unfortunately, I don't think I have enough time to address the open questions, and maybe the UX we want can be driven by the std verification effort. It will give us opportunity to incorporate more user feedback and ensure we have a robust solution.

@celinval celinval closed this Jan 31, 2025
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.

6 participants