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

Enable default analysis flags for CBMC version 6.0+ #8093

Merged
merged 39 commits into from
Dec 13, 2023

Conversation

NlightNFotis
Copy link
Contributor

@NlightNFotis NlightNFotis commented Dec 5, 2023

This is a cleaned up version of #8006.

There are two difference over the previous PR:

  • Primary difference is setting up the --no-standard-checks flag in all of the regression test runners, instead of adjusting flags on each failing test. The reason we need to adjust flags to begin with is that a lot of tests are checking for number of properties or specific labels in the output, which, now that we enable a lot more properties by default, have been invalidated.
  • Presents a cleaner change into cbmc_parse_options and goto_check_c. Previous version rejected a flag that was on by default, such as --pointer-check, this version silently ignores it.

Still to-do:

  • Add new flag to goto-analyzer as well.
  • Add documentation for new flags and behaviour.

@NlightNFotis NlightNFotis added the Version 6 Pull requests and issues requiring a major version bump label Dec 5, 2023
"(assert-to-assume)"
"(assert-to-assume)" \
"(no-bounds-check)(no-pointer-check)(no-signed-overflow-check)" \
"(no-pointer-primitive-check)(no-undefined-shift-check)"
Copy link
Contributor

Choose a reason for hiding this comment

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

Missing "no-div-by-zero-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.

Yeah, this was missed. I've added it now.

Comment on lines 115 to 117
options.set_option("bounds-check", true);
options.set_option("pointer-check", true);
options.set_option("pointer-primitive-check", true);
options.set_option("div-by-zero-check", true);
options.set_option("signed-overflow-check", true);
options.set_option("undefined-shift-check", true);
Copy link
Contributor

Choose a reason for hiding this comment

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

Aren't all of these then re-set later depending on the [no-]standard-checks option?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This code is called depending on whether the no-standard-checks is set.

Copy link
Contributor

Choose a reason for hiding this comment

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

Aren't they called on both line 140 and line 337?

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 see what you mean now. Yeah, that has been eliminated now :) Good catch, it was an artefact of a previous design that set the default options unconditionally, and then if the --no-standard-checks flag was present it was just overriding it.

Now we've moved to a design that sets or doesn't set based on the flag being present.


// Unwinding assertions required in certain cases for sound verification
// results. See https://github.com/diffblue/cbmc/issues/6561 for elaboration.
options.set_option("unwinding-assertions", true);
Copy link
Contributor

Choose a reason for hiding this comment

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

Line 144 below now needs to handle this being set on be default. Maybe also line 287?

Copy link
Contributor

@thomasspriggs thomasspriggs left a comment

Choose a reason for hiding this comment

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

The handling of the malloc checks looks wrong. This is the main blocking comment which needs to be addressed.

My overarching remaining nitpick is that perhaps everything carried out by your duplicated set_default_analysis_flags functions should actually be done elsewhere. If you move all the functionality out of the functions, they will be unneeded and then duplication can be resolved by removing them.

@@ -56,6 +56,25 @@ goto_analyzer_parse_optionst::goto_analyzer_parse_optionst(
{
}

void goto_analyzer_parse_optionst::set_default_analysis_flags(optionst &options)
{
// Checks enabled by default in v6.0+.
Copy link
Contributor

Choose a reason for hiding this comment

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

The code in goto_analyzer_parse_optionst::set_default_analysis_flags and cbmc_parse_optionst::set_default_analysis_flags is duplicated. This is is a potential maintenance issue, to keep them synchronised.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This should stay as it is, because these two functions may be equivalent in form, but they represent different knowledge - the default configuration of two tools that are functionally different (one is a model checker and the other is an abstract interpreter), which only incidentally happens to be similar now, and could very well develop independently in the future.

options.set_option("pointer-primitive-check", true);
options.set_option("div-by-zero-check", true);
options.set_option("signed-overflow-check", true);
options.set_option("undefined-shift-check", true);
Copy link
Contributor

Choose a reason for hiding this comment

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

As per @TGWDB comment, the options in the PARSE_OPTIONS_GOTO_CHECK_NEGATIVE_DEFAULT_CHECKS macro don't need to be in this function. This is because the macro sets the options after this function is called and it will set the value of the option regardless of whether it needs to be true or false.

Copy link
Contributor Author

@NlightNFotis NlightNFotis Dec 7, 2023

Choose a reason for hiding this comment

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

The PARSE_OPTIONS_GOTO_CHECK_NEGATIVE_DEFAULT_CHECKS's main functional aim is to be there to overwrite the flags in case they happen to be different (say, if a user is using default checks, but also --no-div-by-zero-check).

I agree that the end result is setting the flags to true twice, but I like that they are present in set_default_analysis_flags as documentation of the tool's default behaviour at the very least, and also without having to depend on flags being implicitly set to the default values by inverted logic in a different place in the code (goto_check_c.h).


// Default malloc failure profile chosen to be returning null.
options.set_option("malloc-may-fail", true);
options.set_option("malloc-fail-null", true);
Copy link
Contributor

Choose a reason for hiding this comment

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

🚫 This doesn't look right. In develop the malloc-may-fail argument and the malloc-fail-null argument are never added to (or read from) the options. Therefore it appears to me that adding them to the options will have no effect. The command line arguments are read from cmdline and immediately used to setup configt::ansi_ct. See

if(cmdline.isset("malloc-fail-null"))

It might be worth considering implementing the default in the above location, in order to keep all the logic for the malloc checks in the same place.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you for the catch!

I have attempted a fix in 71cda7c that I think should achieve the same end-goal but keep the code a bit cleaner. It achieves that by restricting the knowledge about the standard checks inside the cbmc_parse_optionst and goto_analyzer_parse_optionst. I think that changing the config.set function would distribute the knowledge about default flags (which for now is strictly a CBMC/goto-analyzer thing) into multiple places, making it harder to follow, and making the configuration (for other tools, as config.set is invoked in 30+ places) more convoluted without any direct correspondence to actual flags.


// Unwinding assertions required in certain cases for sound verification
// results. See https://github.com/diffblue/cbmc/issues/6561 for elaboration.
options.set_option("unwinding-assertions", true);
Copy link
Contributor

Choose a reason for hiding this comment

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

As goto_instrument can be used to perform unwinding, shouldn't this new default be applied in that entry point in that 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.

Hm, I think in that case it probably wouldn't matter, because the analysis tools (the two main ones - cbmc and goto-analyzer) would add these, if I understand this correctly.

I need to play with this a bit and get back to you.

Copy link
Contributor

Choose a reason for hiding this comment

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

As unwinding is a transformation, rather than an analysis on its own right, I think this option needs to be set correctly for which ever entry point is performing the the transformation. My current assumption is that the unwinding assertions are added during the unwinding process. So the usual process flow is that the unwinding and the assertions would be done as part of the cbmc entry point. But if unwinding is performed on the goto-program before cbmc then the analysis won't go back and add the assertions which should have been added prior.

Copy link

codecov bot commented Dec 8, 2023

Codecov Report

All modified and coverable lines are covered by tests ✅

Comparison is base (97ab133) 79.08% compared to head (9747f61) 79.09%.

Additional details and impacted files
@@           Coverage Diff            @@
##           develop    #8093   +/-   ##
========================================
  Coverage    79.08%   79.09%           
========================================
  Files         1698     1698           
  Lines       196457   196485   +28     
========================================
+ Hits        155370   155401   +31     
+ Misses       41087    41084    -3     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@@ -59,4 +59,4 @@ elif echo $args_inst | grep -q -- "--dump-c" ; then
rm "${name}${dfcc_suffix}-mod.c"
fi
$goto_instrument --show-goto-functions "${name}${dfcc_suffix}-mod.gb"
$cbmc "${name}${dfcc_suffix}-mod.gb" ${args_cbmc}
$cbmc --no-standard-checks "${name}${dfcc_suffix}-mod.gb" ${args_cbmc}
Copy link
Member

Choose a reason for hiding this comment

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

Please don't do this. It will be very though for anyone to work out what the tests actually do execute when one fails.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hi @kroening, just for clarification:

We were hoping to use this approach as a stop-gap to allow us to get the regression test suite in a way that is all-green again, so that we could merge this in time, seeing as this is the main ticket that's blocking a v6 release.

But the aim was to get this in temporarily, and as soon our v6 release is unblocked, reopen #8006, rebase it and then move to a model where the extra flag is being passed on an individual basis to tests (to localise the information about the test on the individual .desc file).

The original approach (of getting all the .desc readjusted) was found to be time consuming, and we wanted to at least unblock the release before we embark on that.

Is that something that works for you? If not, is there a particular proposal you had mind?

Copy link
Member

Choose a reason for hiding this comment

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

It's ok to use --no-standard-checks on most of the tests; my suggestion is to add it to the .desc file, where everyone will see it, instead of burying it inside a script.

Copy link
Contributor

Choose a reason for hiding this comment

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

I agree that the place for the --no-standard-checks flag is the .desc file of each failing test.
Unfortunately there are about 300 failing tests, so the idea was to avoid having a PR with code changes in the middle of 300 repetitive test fixes, but instead to temporarily add --no-standard-checks to the scripts to pass CI and them fix all the failing test on a subsequent PR aimed solely at fixing the regression tests.

@kroening I hope that this clarifies why the --no-standard-checks flag has been added on the runner script at the moment.

@peterschrammel
Copy link
Member

💡 Since we have now combinations of flags that turn on and off checks, it would be great to output the list of actually active checks to the console.

NlightNFotis and others added 17 commits December 13, 2023 15:54
So that the defaults can be selectively overridden, whether they are
initially on or off.
This allows for parsing the whole set of options regardless of whether
the default is true or false. This then simplifies the usage of the
macro as the separate option parsing no longer depends on if
"no-standard-checks" is specified.
The `optionst` class essentially uses tri-state logic for booleans,
where an option may be true, false or unset. `is_set` will return `true`
for both the true and false options. Therefore we need `get_bool_option`
to get the state of whether the option is set to true or false.
As the default is now to switch on the unwinding-assertions, we don't
want a user to have to specify `--no-unwinding-assertions` in order to
use `--cover`.
It will be handled in next PR.
@NlightNFotis NlightNFotis requested a review from a team as a code owner December 13, 2023 15:54
Copy link
Contributor

@thomasspriggs thomasspriggs left a comment

Choose a reason for hiding this comment

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

I am approving as the malloc changes have been removed, for handling this separately.

Copy link
Member

@peterschrammel peterschrammel left a comment

Choose a reason for hiding this comment

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

Approving to unblock the pre-release, given the promise that open requests come in a separate PR.

@NlightNFotis NlightNFotis merged commit 41af31c into diffblue:develop Dec 13, 2023
@NlightNFotis NlightNFotis deleted the new_flags_on_clean branch December 13, 2023 23:36
@tautschnig tautschnig mentioned this pull request Dec 14, 2023
4 tasks
tautschnig added a commit to tautschnig/cbmc that referenced this pull request Dec 14, 2023
With additional checks turned on as of diffblue#8093, we failed CSmith tests
with (legitimate) pointer property failures in `strcmp`. These are
caused by trying to compare `argv[1]` to a string. As we do not model
`argv` in these tests, `argv[1]` was not a valid pointer. This fix just
removes the string comparison, which is only used for turning on/off
debug output in test execution.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Version 6 Pull requests and issues requiring a major version bump
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

6 participants