-
Notifications
You must be signed in to change notification settings - Fork 92
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
modifies
Clauses for Function Contracts
#2800
modifies
Clauses for Function Contracts
#2800
Conversation
modifies
Clauses for Function Contracts
d168666
to
0c3cea7
Compare
b968497
to
9362624
Compare
|
Thanks for the review. I'll get to your individual changes in a bit but I thought I'd address this question first.
Technically yes, we could compute it then, however the information relies on the output of the reachability analysis, so we'd have to run a separate reachability pass. If you're happy with that overhead, and also the complexity of having two separate passes or a generic, visitor-like, reusable pass then yes, we can precompute. |
That's because you need the mangled name for the function, right? If you need the result of the reachability analysis, the upfront analysis won't work, since the harness could have stubs that influence the reachability result. Another possibility is to use the QueryDb which is already shared between KaniCompiler and GotocCodegenBackend |
Not just the mangled name of the function, but the mangled name of the instance which we only know post-reachability. |
I can do that, however there is actually a comment in the code gen "Queries shouldn't change today once codegen starts." which I would be violating. Just so you know |
Moved contracts code gen functions to separate module Moved `Pointer` trait to `internal` module Remove channel based modifies contract communication
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a few more changes, and I think we'll be ready to go. Thanks
## What's Changed * `modifies` Clauses for Function Contracts by @JustusAdam in #2800 * Fix ICEs due to mismatched arguments by @celinval in #2994. Resolves the following issues: * #2260 * #2312 * Enable powf*, exp*, log* intrinsics by @tautschnig in #2996 * Upgrade Rust toolchain to nightly-2024-01-24 by @celinval @feliperodri @qinheping **Full Changelog**: kani-0.45.0...kani-0.46.0 By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses. --------- Signed-off-by: Felipe R. Monteiro <felisous@amazon.com> Co-authored-by: Celina G. Val <celinval@amazon.com>
Extends the function contract functionality with a
modifies
clause.The design is different from #2594 but serves a similar purpose. The
modifies
clause allows the user to specify which parts of a structure a function may assign to. Essentially refining themut
annotation.We allow arbitrary (side-effect free) expressions in the
modifies
clause. The expressions are evaluated as part of the preconditions and passed to the function-under-verification as additional arguments. CBMC is then instructed to check that those locations are assigned. Aliasing means that this also adds the location in the original structure to the write set.Each expression must return a pointer to a value that implements
Arbitrary
. On replacement we then simply assign*ptr = kani::any()
, relying again on aliasing to update the original structure.Additional tests for the new functionality are provided.
Resolves #2594
Open Questions
API divergence from CBMC (accepted)
The current design goes roughly as follows: We start with a
modifies
annotation on a functionAnd from this we generate code to the effect of (simplified here)
Unlike CBMC we expect
obj.some_expr()
to be of a pointer type (*const
,*mut
,&mut
or&
) that points to the object which is target of the modification. So if we had at : &mut T
that was modified, CBMC would expect its assigns clause to say*t
, but we expectt
(no dereference).The reason is that the code we generate uses the workaround of creating an alias to whichever part of
obj
is modified and registers the alias with CBMC (thereby registering the original also). If we generated code where the right side oflet modified_1 =
is not of pointer type, then the object is moved to the stack and the aliasing destroyed.The open questions is whether we are happy with this change in API. (Yes)
Test cases when expressions are used in the clause.
With more complex expressions in the modifies clause it becomes hard to define good test cases because they reference generated code as in this case:
This passes (as it should) and when commenting out the
modifies
clause we get this error:The information in this error is very non-specific, hard to read and brittle. How should we define robust "expected" test cases for such errors?
Corner Cases / Future Improvements
modifies
clauses #2907modifies
clauses #2908modifies
clauses cause unsound vacuity #2909TODOs
Rc
+ (RefCell
orunsafe
) (see Support for encapsulated mutability inmodifies
clauses #2907)Vec
(see Divergingmodifies
clauses cause unsound vacuity #2909)nondet-static-exclude
always uses the correct filepath (relative or absolute)modifies
clauses.By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses.