Skip to content

Unify havocing codegen within code contracts #6292

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

Merged
merged 2 commits into from
Aug 18, 2021

Conversation

SaswatPadhi
Copy link
Contributor

@SaswatPadhi SaswatPadhi commented Aug 12, 2021

Resolves #6235.

In this PR, we unify the havocing code generation for both loop & function contracts.

This fixes multiple known issues:

  1. (function contracts) entire arrays were not being havoced
  2. (loop contracts) pointers not checked for nullness before havocing
  • Each commit message has a non-empty body, explaining why the change was made.
  • Methods or procedures I have added are documented, following the guidelines provided in CODING_STANDARD.md.
  • n/a The feature or user visible behaviour I have added or modified has been documented in the User Guide in doc/cprover-manual/
  • Regression or unit tests are included, or existing tests cover the modified code (in this case I have detailed which ones those are in the commit message).
  • n/a My commit message includes data points confirming performance improvements (if claimed).
  • My PR is restricted to a single feature or bugfix.
  • White-space or formatting changes outside the feature-related changed lines are in commits of their own.

@SaswatPadhi SaswatPadhi added bugfix aws Bugs or features of importance to AWS CBMC users Code Contracts Function and loop contracts labels Aug 12, 2021
@SaswatPadhi SaswatPadhi self-assigned this Aug 12, 2021
@SaswatPadhi SaswatPadhi force-pushed the havoc_fix branch 5 times, most recently from 0cbf501 to d84d2b4 Compare August 12, 2021 00:56
@codecov
Copy link

codecov bot commented Aug 12, 2021

Codecov Report

Merging #6292 (55cbcb7) into develop (a0a1329) will decrease coverage by 0.00%.
The diff coverage is 97.87%.

Impacted file tree graph

@@             Coverage Diff             @@
##           develop    #6292      +/-   ##
===========================================
- Coverage    75.98%   75.98%   -0.01%     
===========================================
  Files         1510     1512       +2     
  Lines       163467   163471       +4     
===========================================
- Hits        124213   124209       -4     
- Misses       39254    39262       +8     
Impacted Files Coverage Δ
src/goto-instrument/contracts/assigns.h 100.00% <ø> (ø)
src/goto-instrument/havoc_loops.cpp 0.00% <0.00%> (ø)
src/goto-instrument/loop_utils.cpp 90.62% <ø> (-3.93%) ⬇️
src/goto-instrument/contracts/assigns.cpp 98.29% <100.00%> (-0.25%) ⬇️
src/goto-instrument/contracts/contracts.cpp 92.59% <100.00%> (ø)
src/goto-instrument/havoc_utils.cpp 100.00% <100.00%> (ø)
src/goto-instrument/havoc_utils.h 100.00% <100.00%> (ø)
src/goto-instrument/k_induction.cpp 96.22% <100.00%> (ø)
src/solvers/smt2/smt2_conv.cpp 66.50% <0.00%> (-0.20%) ⬇️
... and 1 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 3092e7b...55cbcb7. Read the comment docs.

@SaswatPadhi SaswatPadhi changed the title Unify havocing within code contracts Unify havocing codegen within code contracts Aug 12, 2021
Copy link
Collaborator

@feliperodri feliperodri left a comment

Choose a reason for hiding this comment

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

Thanks for implementing this fix!! Just a few comments.

Comment on lines +23 to +59
void append_havoc_code(
const source_locationt source_location,
const modifiest &modifies,
goto_programt &dest);

void append_object_havoc_code_for_expr(
const source_locationt source_location,
const exprt &expr,
goto_programt &dest);

void append_scalar_havoc_code_for_expr(
const source_locationt source_location,
const exprt &expr,
goto_programt &dest);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why the suffix "append"? Perhaps we can come up with more intuitive names. What do you think about havoc_code, havoc_object, and havoc_scalar?

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 original prefix was build and it was inserting goto statements at the end of the dest goto program. I was always confused about whether it adds the statements at the beginning or at the end, so I just changed build -> append. What part of the name is unintuitive?

The names havoc_code, havoc_object, and havoc_scalar seem okay but lead to the same confusion as build. Also notice that append_havoc_code takes an entire modifies set, but the append_*_havoc_code_for_expr functions take exprt.

The editor autocompletes anyway, so I just use longer function names that are more explicit about their effect.

Copy link
Collaborator

Choose a reason for hiding this comment

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

This is not a blocker, since it is probably just a style matter. For me, clear and concise method names yields clear code.

I was always confused about whether it adds the statements at the beginning or at the end, so I just changed build -> append.

I'd add this information to a header comment in each method. This will also help us to build document for this file using Doxygen. Some editors also pick up this information. For instance, take a look at this method:

/// \brief Replace all calls to each function in the list with that function's
/// contract
///
/// Use this function when proving code that calls into an expensive function,
/// `F`. You can write a contract for F using __CPROVER_requires and
/// __CPROVER_ensures, and then use this function to replace all calls to `F`
/// with an assertion that the `requires` clause holds followed by an
/// assumption that the `ensures` clause holds. In order to ensure that `F`
/// actually abides by its `ensures` and `requires` clauses, you should
/// separately call `code_constractst::enforce_contracts()` on `F` and verify
/// it using `cbmc --function F`.
///
/// \return `true` on failure, `false` otherwise
bool replace_calls(const std::set<std::string> &functions);

Also notice that append_havoc_code takes an entire modifies set, but the append_*_havoc_code_for_expr functions take exprt.

This is the type of information that could easily go to a comment header or inferred just by looking at the parameters.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks, I agree I should add some comments here regardless, but for now I think I will leave append_*_havoc_code_for_expr and append_havoc_code, unless there is something specific that's incorrect / confusing about these names.

What do you think about havoc_code, havoc_object, and havoc_scalar?

I thought a bit more about these names, but havoc_code seems incorrect -- it doesn't havoc a codet but a set<exprt>.

I guess we can revisit this later when we add comments & documentation for our functions.

Copy link
Contributor

Choose a reason for hiding this comment

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

Personally, I like the append_*_ naming :-)

Comment on lines 186 to 192
modifiest modifies;
std::for_each(
targets.begin(),
targets.end(),
[&modifies](const assigns_clause_targett *t) {
modifies.insert(to_address_of_expr(t->get_direct_pointer()).object());
});
Copy link
Collaborator

Choose a reason for hiding this comment

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

Very clean 👏 nice!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

😄 Thanks!

While writing this transformation, I noticed that targets is a vector, unlike modifies, which is a set. If we write the same expression twice in the __CPROVER_assigns clause, would we end up havocing / enforcing it twice? Or, does the parser / typechecker somehow guard against this?

Copy link
Collaborator

Choose a reason for hiding this comment

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

If we write the same expression twice in the __CPROVER_assigns clause, would we end up havocing / enforcing it twice? Or, does the parser / typechecker somehow guard against this?

We don't have any regression tests that cover this behavior. Could you write a regression test that cover this scenario for both loop contracts and function contracts?

While writing this transformation, I noticed that targets is a vector, unlike modifies, which is a set.

Could you turn targets into a set too? Regardless of our type-checking procedure, set would be a more appropriate data structure here.

These modifications might be part of a separate PR. I'm happy to implement it too if that's the case.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Currently this is not a concern for loops because we don't allow manual assigns clause annotation yet.

I would separate this refactor (vector -> set) into another PR though. I'll open an internal ticket to track it.

@SaswatPadhi SaswatPadhi force-pushed the havoc_fix branch 2 times, most recently from 209f403 to 64fe788 Compare August 12, 2021 04:09
Copy link
Collaborator

@feliperodri feliperodri left a comment

Choose a reason for hiding this comment

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

I don't have any more blocking comments. 🚀

This change fixes multiple known issues:
- (function contracts) entire arrays were not being havoced
- (loop contracts) pointers not checked for nullness before havocing
@SaswatPadhi SaswatPadhi merged commit 1268cc1 into diffblue:develop Aug 18, 2021
@SaswatPadhi SaswatPadhi deleted the havoc_fix branch August 18, 2021 14:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
aws Bugs or features of importance to AWS CBMC users bugfix Code Contracts Function and loop contracts
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Replace with contracts - havoc entire array content
3 participants