Skip to content

Disable unnecessary pointer checks, enable necessary pointer checks i… #6459

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

Conversation

remi-delmas-3000
Copy link
Collaborator

@remi-delmas-3000 remi-delmas-3000 commented Nov 16, 2021

This PR fixes some performance issues with assigns clause checking for function and loop contracts.

The problem was that the goto variables and instructions generated to instrument the checks were themselves re-instrumented with automatic VCCs in subsequent passes, causing an explosion in the number of VCCs (with unwanted VCCs representing up to 85% of the total VCCs in some problems).

Instructions performing CAR inclusion checks are read-only logical expressions whose evaluation cannot fail so we can safely disable automatic checks on them.

CAR snapshotting instructions however perform some pointer arithmetic and need to be ultimately checked for pointer overflow.

In this PR:

  • we disable all pointer checks on CAR inclusion checking instructions
  • we enable pointer overflow checks on CAR snapshot instructions

The disable pragmas guard against reinstrumentation in later passes, and the enable pragmas make sure necessary checks will eventually be instantiated before analysis.

  • 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.
  • 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).
  • 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.

@@ -116,6 +116,8 @@ const symbolt &new_tmp_symbol(
const typet &type,
const source_locationt &location,
const irep_idt &mode,
symbol_table_baset &symtab);
symbol_table_baset &symtab,
std::string suffix = "tmp_cc");
Copy link
Collaborator

Choose a reason for hiding this comment

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

This new parameter needs a doxygen comment above

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

fixed

@codecov
Copy link

codecov bot commented Dec 2, 2021

Codecov Report

Merging #6459 (e2f4fec) into develop (d8e5aac) will increase coverage by 0.00%.
The diff coverage is 100.00%.

Impacted file tree graph

@@           Coverage Diff            @@
##           develop    #6459   +/-   ##
========================================
  Coverage    76.07%   76.08%           
========================================
  Files         1548     1548           
  Lines       166362   166387   +25     
========================================
+ Hits        126567   126591   +24     
- Misses       39795    39796    +1     
Impacted Files Coverage Δ
src/goto-instrument/contracts/assigns.h 100.00% <ø> (ø)
src/goto-instrument/contracts/utils.h 100.00% <ø> (ø)
src/goto-instrument/contracts/assigns.cpp 97.24% <100.00%> (+0.30%) ⬆️
src/goto-instrument/contracts/contracts.cpp 95.44% <100.00%> (+0.05%) ⬆️
src/goto-instrument/contracts/utils.cpp 93.54% <100.00%> (+0.69%) ⬆️
src/solvers/flattening/bv_utils.cpp 77.33% <0.00%> (-0.21%) ⬇️

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 adfd71d...e2f4fec. Read the comment docs.

Copy link
Collaborator

@tautschnig tautschnig left a comment

Choose a reason for hiding this comment

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

Generally ok with this, but the last commit introduces/modifies various tests and it is not obvious which tests are just additional tests, or which code changes these tests relate to.

Comment on lines 148 to 155
return get_fresh_aux_symbol(
type,
id2string(location.get_function()) + "::tmp_cc",
"tmp_cc",
id2string(location.get_function()) + "::",
suffix,
location,
mode,
symtab);
Copy link
Collaborator

Choose a reason for hiding this comment

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

While at it: should this code also be modified to have those symbols show up in counterexample traces? I found myself having a hard time understanding counterexamples for none of the assignments to these variables show up, but failing assertions then refer to them. The change required to facilitate this:

symbolt &new_symbol = get_fresh_aux_symbol(...);
new_symbol.is_auxiliary = false;
return new_symbol;

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Adding a new function argument 'is_auxiliary' to control that symbol per symbol.

@@ -52,14 +52,16 @@ static const slicet normalize_to_slice(const exprt &expr, const namespacet &ns)
}

const symbolt assigns_clauset::conditional_address_ranget::generate_new_symbol(
const std::string &prefix,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Random place for comment, and primarily for future reference: I would like to see commits like this be a pull request of their own. Changing the names of CAR instrumentation variables really has nothing to do with disabling selected checks.

Comment on lines 914 to 915
source_locationt &location_no_checks =
instruction_it->source_location_nonconst();
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do you really want or need to take a reference here? The reference will ensure (but is that desired?) that checks are disabled on the function call. Otherwise, I would have expected that you'd be taking a copy here, at which point you want to use source_location() instead of source_location_nonconst().

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

fixed

@@ -1175,6 +1175,10 @@ void code_contractst::check_frame_conditions(
else if(instruction_it->is_dead())
{
const auto &symbol = instruction_it->dead_symbol();
source_locationt &location_no_checks =
instruction_it->source_location_nonconst();
disable_pointer_checks(location_no_checks);
Copy link
Collaborator

Choose a reason for hiding this comment

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

As above: is the reference intentional?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

fixed

Copy link
Collaborator

Choose a reason for hiding this comment

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

We could add a comment here again explaining "why" is safe to always remove pointer checks in this location.

assigns.generate_inclusion_check(car), instruction_it->source_location()));
assertion.instructions.back().source_location_nonconst().set_comment(
source_locationt location_no_checks =
instruction_it->source_location_nonconst();
Copy link
Collaborator

Choose a reason for hiding this comment

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

Certainly source_location() instead of source_location_nonconst().

@@ -40,4 +42,4 @@ We also check (using positive regex matches above) that
`**p` should be assignable in one case and should not be assignable in the other.

Finally, we check that there should be no "internal" assertion failures
on `tmp_cc` variables used to track CARs.
on `__car_valid`, `__car_ub`, `__car_lb` variables used to track CARs.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Changes in this file should be folded into the commit introducing the new names.

@@ -0,0 +1 @@
Reading GOTO program from '__CPROVER_file_local_s2n_hash_c_s2n_evp_hash_reset_with_contracts_harness.c.goto'
Copy link
Collaborator

Choose a reason for hiding this comment

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

What is the meaning of this file?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

this is a debugging session leftover, removing it

@remi-delmas-3000 remi-delmas-3000 force-pushed the assigns-clause-perf-optim branch from 7c37804 to 0b7535c Compare December 3, 2021 16:26
@remi-delmas-3000
Copy link
Collaborator Author

All review comments were addressed

@remi-delmas-3000 remi-delmas-3000 force-pushed the assigns-clause-perf-optim branch from 0b7535c to 3aee2f7 Compare December 3, 2021 18:09
@tautschnig tautschnig dismissed jimgrundy’s stale review December 3, 2021 18:40

Issue has been addressed

@remi-delmas-3000 remi-delmas-3000 force-pushed the assigns-clause-perf-optim branch from 3aee2f7 to e2f4fec Compare December 3, 2021 18:45
@tautschnig tautschnig merged commit 1e8e495 into diffblue:develop Dec 3, 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.

I was a bit too late to the party, but I'll leave the comments here to be addressed on another PR.

Comment on lines +32 to +34
^.*__car_valid.*: FAILURE$
^.*__car_lb.*: FAILURE$
^.*__car_ub.*: FAILURE$
Copy link
Collaborator

Choose a reason for hiding this comment

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

nitpick: I'd prefer even more readable names for users: __car_valid, __car_lower_bound, and __car_upper_bound. However, the fact that these variables exist should be transparent to users. Why would this variables appear as failures? I guess you want to make sure here there are no memory safety errors in any operation using these variables, is that correct?

Comment on lines +64 to +66
const std::string &prefix,
const typet &,
const source_locationt &) const;
Copy link
Collaborator

Choose a reason for hiding this comment

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

For consistency, add the name of the remaining parameters or remove prefix.

Comment on lines +145 to +146
symbol_table_baset &symtab,
std::string suffix,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
symbol_table_baset &symtab,
std::string suffix,
symbol_table_baset &symtab,
std::string &suffix,

Comment on lines 114 to 115
/// \param suffix: Suffix to use to generate the unique name
/// \param is_auxiliary: Do not print symbol in traces if true (default = false)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
/// \param suffix: Suffix to use to generate the unique name
/// \param is_auxiliary: Do not print symbol in traces if true (default = false)
/// \param suffix: Suffix to use to generate the unique name.
/// \param is_auxiliary: Do not print symbol in traces if true (default = false).

Comment on lines +91 to +92
// adding pragmas to the location to selectively disable checks
// where it is sound to do so
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think a brief explanation of "why" is sound to disable checks here would be more helpful, since one can easily infer this comment from the code.


// the computation of the CAR upper bound can overflow into the object ID bits
// of the pointer with very large allocation sizes.
// We enable pointer overflow checks to detect such cases.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
// We enable pointer overflow checks to detect such cases.
// We always enable pointer overflow checks to detect such cases.

Comment on lines +151 to +153
// remark: both lb and ub are derived from the same object so checking
// same_object(upper_bound_address_var, lhs.upper_bound_address_var)
// is redundant
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nice!

Suggested change
// remark: both lb and ub are derived from the same object so checking
// same_object(upper_bound_address_var, lhs.upper_bound_address_var)
// is redundant
// Both lb and ub are derived from the same object so checking
// same_object(upper_bound_address_var, lhs.upper_bound_address_var)
// is redundant

@@ -911,6 +911,8 @@ void code_contractst::instrument_call_statement(
}
else if(callee_name == "free")
{
source_locationt location_no_checks = instruction_it->source_location();
disable_pointer_checks(location_no_checks);
Copy link
Collaborator

Choose a reason for hiding this comment

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

We could add a comment here again explaining "why" is safe to always remove pointer checks in this location.

@@ -1175,6 +1175,10 @@ void code_contractst::check_frame_conditions(
else if(instruction_it->is_dead())
{
const auto &symbol = instruction_it->dead_symbol();
source_locationt &location_no_checks =
instruction_it->source_location_nonconst();
disable_pointer_checks(location_no_checks);
Copy link
Collaborator

Choose a reason for hiding this comment

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

We could add a comment here again explaining "why" is safe to always remove pointer checks in this location.

assertion.instructions.back().source_location_nonconst().set_comment(
source_locationt location_no_checks =
instruction_it->source_location_nonconst();
disable_pointer_checks(location_no_checks);
Copy link
Collaborator

Choose a reason for hiding this comment

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

We could add a comment here again explaining "why" is safe to always remove pointer checks in this location.

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 aws-high Code Contracts Function and loop contracts
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants