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

Fix spurious overflow counter examples. (#558) #647

Merged
merged 5 commits into from
Nov 23, 2021

Conversation

celinval
Copy link
Contributor

@celinval celinval commented Nov 15, 2021

Description of changes:

RMC was treating all arithmetic operations as non-wrapping which was triggering a lot of spurious counter examples. Instead of relying on cbmc generated overflow checks, we are not explicitly encoding checks for non-wrapping operations.

Resolved issues:

Resolves #558

Call-outs:

I created #646 to track implementing more checks that we currently don't support. Except for shift left and division by 0, I believe CBMC doesn't have any mechanism to check them.

Testing:

  • How is this change tested?

I created a bunch of new tests.

  • Is this a refactor change?

I guess.

Checklist

  • Each commit message has a non-empty body, explaining why the change was made
  • Methods or procedures are documented
  • Regression or unit tests are included, or existing tests cover the modified code
  • My PR is restricted to a single feature or bugfix

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 November 15, 2021 22:48
@@ -815,7 +815,7 @@ impl Expr {
&& (lhs.typ.is_pointer() || lhs.typ.is_numeric() || lhs.typ.is_vector())
|| (lhs.typ.is_pointer() && rhs.typ.is_integer())
}
Plus => {
Plus | OverflowMinus | OverflowMult | OverflowPlus => {
Copy link
Contributor

@zhassan-aws zhassan-aws Nov 16, 2021

Choose a reason for hiding this comment

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

Do the cases here (e.g. LHS is a pointer and RHS is an integer) apply to overflow addition/subtraction/multiplication? EDIT: I see now that some of those cases apply to intrinsics.

Copy link
Contributor

Choose a reason for hiding this comment

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

The argument types have to remain the same for each operation (i.e., OverflowMinus goes with Minus).

Copy link
Contributor Author

@celinval celinval Nov 16, 2021

Choose a reason for hiding this comment

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

Makes sense. Do you know why the minus has different requirements?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, minus allows both operands to be pointers because it is valid to compute offsets between them. This does not apply to plus because adding two pointers will likely result in another pointer to who-knows-where.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, I hadn't thought about that. Good point.

I removed the vector from the list since it doesn't look like CBMC overflow operation actually accepts C arrays.While trying to reproduce the issue to file a bug report, I noticed that CBMC was printing the following warning:

warning: ignoring overflow-*
  * type: bool
  0: array
      * type: array
          * #source_location: nil
          * size: constant
              * type: signedbv
                  * width: 64
                  * #c_type: signed_long_int
              * value: 2
          0: signedbv
              * width: 8
      0: constant
          * type: signedbv
              * width: 8
          * value: 0
      1: constant
          * type: signedbv
              * width: 8
          * value: 0
  1: array
      * type: array
          * #source_location: nil
          * size: constant
              * type: signedbv
                  * width: 64
                  * #c_type: signed_long_int
              * value: 2
          0: signedbv
              * width: 8
      0: constant
          * type: signedbv
              * width: 8
          * value: 0
      1: constant
          * type: signedbv
              * width: 8
          * value: 0

Copy link
Contributor

@zhassan-aws zhassan-aws left a comment

Choose a reason for hiding this comment

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

Looks great! The new tests are very good!

let sum1 = a.wrapping_add(b);
let sum2 = a.checked_add(b);
assert!(sum0 == sum1);
assert!(sum1 >= a || sum2.is_none());
Copy link
Contributor

Choose a reason for hiding this comment

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

Do you want to add sum1 >= b as well?

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.

The changes here heavily rely on -C overflow-checks=on. Can we add a check to our back-end to ensure the flag is always set?

@@ -815,7 +815,7 @@ impl Expr {
&& (lhs.typ.is_pointer() || lhs.typ.is_numeric() || lhs.typ.is_vector())
|| (lhs.typ.is_pointer() && rhs.typ.is_integer())
}
Plus => {
Plus | OverflowMinus | OverflowMult | OverflowPlus => {
Copy link
Contributor

Choose a reason for hiding this comment

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

The argument types have to remain the same for each operation (i.e., OverflowMinus goes with Minus).

compiler/rustc_codegen_rmc/src/codegen/intrinsic.rs Outdated Show resolved Hide resolved
Comment on lines 183 to 185
// Intrinsics which encode a simple wrapping arithmetic operation
macro_rules! codegen_wrapping_op {
($f:ident) => {{ self.binop(p, fargs, |a, b| a.$f(b)) }};
}
Copy link
Contributor

Choose a reason for hiding this comment

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

A few lines below there is codegen_intrinsic_binop which does the same thing. Why did you add this?

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 was trying to make it explicit that this is a wrapping operation. To avoid others to inadvertently using the wrong operation in the future.

I could modify this to just call the binop one or remove this. Any preference?

@celinval
Copy link
Contributor Author

The changes here heavily rely on -C overflow-checks=on. Can we add a check to our back-end to ensure the flag is always set?

Should we allow users to turn them off though? What if I add a check with a warning if the flag is off?

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.

Looking good! Of course, we can change the check in the near future to support other use cases, but I do not feel comfortable with our codegen depending on this flag and not requiring it.

@tedinski
Copy link
Contributor

Doesn't this mean we no longer spot overflows in unsafe code?

@celinval
Copy link
Contributor Author

Doesn't this mean we no longer spot overflows in unsafe code?

That's a great question! I should definitely add test cases for that.

We are still checking for overflow in unsafe code. Regular arithmetic operations are always checked no matter where they show up in the code.

@celinval
Copy link
Contributor Author

This should be check_mul

I wonder how this test even passed. o.O

@adpaco-aws
Copy link
Contributor

I wonder how this test even passed. o.O

Probably because CBMC is not finding the function to verify and that is understood as a verification failure.

@celinval celinval merged commit b04b7a9 into model-checking:main Nov 23, 2021
@celinval celinval deleted the issue-558 branch November 23, 2021 19:18
@adpaco-aws adpaco-aws mentioned this pull request Apr 19, 2022
tedinski pushed a commit to tedinski/rmc that referenced this pull request Apr 22, 2022
…hecking#647)

We cannot easily specify which arithmetic operations are wrapping ones to CBMC. Thus, CBMC was generating overflow checks for wrapping operations which were generating spurious failures. This change disables some of those CBMC checks. We replace them by using rustc overflow checks for regular operations and by explicitly adding checks to unchecked operations.
tedinski pushed a commit to tedinski/rmc that referenced this pull request Apr 25, 2022
…hecking#647)

We cannot easily specify which arithmetic operations are wrapping ones to CBMC. Thus, CBMC was generating overflow checks for wrapping operations which were generating spurious failures. This change disables some of those CBMC checks. We replace them by using rustc overflow checks for regular operations and by explicitly adding checks to unchecked operations.
tedinski pushed a commit to tedinski/rmc that referenced this pull request Apr 26, 2022
…hecking#647)

We cannot easily specify which arithmetic operations are wrapping ones to CBMC. Thus, CBMC was generating overflow checks for wrapping operations which were generating spurious failures. This change disables some of those CBMC checks. We replace them by using rustc overflow checks for regular operations and by explicitly adding checks to unchecked operations.
tedinski pushed a commit that referenced this pull request Apr 27, 2022
We cannot easily specify which arithmetic operations are wrapping ones to CBMC. Thus, CBMC was generating overflow checks for wrapping operations which were generating spurious failures. This change disables some of those CBMC checks. We replace them by using rustc overflow checks for regular operations and by explicitly adding checks to unchecked operations.
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.

Spurious overflow failures with Result/Error types
4 participants