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

Audit for ptr_offset_from #1099

Merged
merged 9 commits into from
Apr 27, 2022
Merged

Conversation

adpaco-aws
Copy link
Contributor

@adpaco-aws adpaco-aws commented Apr 23, 2022

Description of changes:

Adds an arithmetic overflow check for ptr_offset_from and removes the __CPROVER_same_object check because CBMC applies it to the arithmetic operation by default.

As with offset, I had concerns because there were no checks for the pointers staying within bounds of the object. So I added __CPROVER_r_ok irep expression and used it, just to find that a bunch of regressions fail.

Resolved issues:

Part of #727

Call-outs:

Testing:

  • How is this change tested? Existing tests.

  • Is this a refactor change? No.

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.

@adpaco-aws adpaco-aws requested a review from a team as a code owner April 23, 2022 16:02
@@ -873,6 +874,7 @@ impl Expr {
(lhs.typ == rhs.typ && lhs.typ.is_integer())
|| (lhs.typ.is_pointer() && rhs.typ.is_integer())
}
ROk => lhs.typ.is_pointer() && rhs.typ.is_c_size_t(),
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not sure ROk is properly classed as a binary operator

Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In my first attempt I declared it as a unary operator but CBMC complained that two arguments were expected for __CPROVER_r/w_ok, so that is why I implemented this. I can remove if it's going to be a blocker.

Copy link
Contributor

Choose a reason for hiding this comment

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

My concern had been more whether we should think of it as a binop, or as a CBMC intrinsic. But we can merge this PR and have a separate ticket to track that. #1111

let cast_src_ptr = src_ptr.clone().cast_to(Type::ssize_t());
let offset = cast_dst_ptr.sub_overflow(cast_src_ptr);
let overflow_check = self.codegen_assert(
offset.overflowed.not(),
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 cause performance problems

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 couldn't come up with a test for this overflow check and then I realized it's wrong. The overflow check has to be done for the distance in bytes, which is what we do now. An expected test for the overflow case is included.

@@ -878,26 +878,28 @@ impl<'tcx> GotocCtx<'tcx> {
/// https://doc.rust-lang.org/std/intrinsics/fn.ptr_offset_from.html
Copy link
Contributor

Choose a reason for hiding this comment

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

There are a bunch of checks, and we're only checking some of them

Both the starting and other pointer must be either in bounds or one byte past the end of the same [allocated object](https://doc.rust-lang.org/std/ptr/index.html#allocated-object).

Both pointers must be derived from a pointer to the same object. (See below for an example.)

The distance between the pointers, in bytes, must be an exact multiple of the size of T.

The distance between the pointers, in bytes, cannot overflow an isize.

The distance being in bounds cannot rely on “wrapping around” the address space.

],
loc,
)
// Check that the computation would not overflow an `isize`
Copy link
Contributor

Choose a reason for hiding this comment

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

Why did you remove the same_object check

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The same_object check is being done by CBMC by default. I converted the test we already had for it into an expected test so we ensure the "same object violation" stays there.

@adpaco-aws
Copy link
Contributor Author

Please check the most recent version, there are 4 tests now for this intrinsic.

@danielsn danielsn merged commit d23d8fd into model-checking:main Apr 27, 2022
@adpaco-aws adpaco-aws mentioned this pull request Apr 27, 2022
tedinski pushed a commit that referenced this pull request Apr 27, 2022
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