Repository navigation
T2: differential execution of verdicts, nightly in CI - #102
Merged
Merged
Conversation
…-instrumented runs of the same source.
…ms, and character types.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Nothing in CI checked a verdict against the program it is about. The soundness investigation of the 0.2 plan did, by hand: it ran 484 contracted functions natively under UBSan and compared the runs with cpp-verify's verdicts, which is how it found the wrong verdicts F38 to F42. Exit criterion 1 requires that check in CI. This is plan item T2.
The investigation's framework is now
clang/utils/cppverify-differential, and CI runs it every night.What it does
For each case, a contracted C++ function with its pre- and postcondition restated in Python, the tool:
auto,bitvector, andintegerencodings and cvc5, or BMC at bounds 6 and 10;clang++ -fverify-contracts -fno-verify(contracts emit no code) and-fsanitize=undefined -fsanitize-trap=undefined;PROT_NONEpage and then starts after one, and each run has an alarm;It reports three kinds of problem, and exits with 1 when there is one:
Verified, orBoundedSafefor an input within the bound, yet an admitted input has undefined behavior or breaks the postcondition.A failure is evidence relative to the contracts it uses, so the tool does not expect every counterexample to reproduce. These are classified rather than reported:
m_weak_post, whose callee promises less than it does);Changes from the investigation's framework
-fverify-contracts -fno-verify, which also exercises the compile path.c_old_param_looptook over 8 minutes and was still running. The whole set now takes 344 s with 32 jobs.hash(), which differs from process to process. They are now seeded with the CRC-32 of the name.c_spec_u_ret: the oracle was written before explicit specs became mathematical.u(x)isx, sopost(u(x) >= 0)is false for negativex, and the oracle now says so;m_weak_post,st_pass_by_value(callee contracts),l_mul_acc_overflow(an inductive iteration): relative to an abstraction;l_decreases_wrong_sign(termination),m_conv_arg_pre_violated(a callee'sprecondition): not observable by a run;c_cast_contract_narrow_math: its postcondition(int)(x + 1) == x + 1 || x == 2147483647is undefined atINT_MAX, since an explicit cast in a contract is checked and the left operand comes first._BitInt(65)cases stated their modulus as the literal36893488147419103232(2^65), which no C++ integer type holds, so cpp-verify and clang rejected the file. They now write((__int128)1 << 65). All 15 65-bit cases verify or fail consistently with execution.p_struct_swap, which has no inputs, is verified without a harness.model, so it is not replayed. The investigation's script filled in zeros there, and the port first did too, which reported(0, 0)as a bad counterexample.Results
On
mainplus #101 and #100 (a release build), every case in every configuration has no problem:518 cases, 0 problems, 344 s with 32 jobs on 64 cores. That is 484 cases, plus the 34 pointer cases rerun under BMC.Out of 1,982 verdicts:
How each counterexample was classified:
On suites 1, 2, and 4, which the investigation's framework also finished, 154 of 155 cases have the same verdicts in every configuration. The other one,
shl_assign_i8_20with--int-encoding=integer, went fromverifiedtosolver.timeoutunder load.CI
.github/workflows/cppverify-differential.ymlruns nightly and on demand. It builds clang and cpp-verify (release, from the release CI cache), installs cvc5 1.4.2, runs every case, and uploads the JSON report.clang/test/Verify/differential.testruns the tool's own seven cases on every change. Two of them state their contract wrongly in Python on purpose, so that a right verdict reads as UNSOUND and a right counterexample as BADCEX. One reads past its buffer, which the guard page must trap, and one has a contract undefined at an input.Each mutant below, applied alone, fails
differential.test:Docs
docs_examples.testchecks.Checked
differential.test,docs_examples.test, anddocs_coverage.testpass.A follow-up for the plan: cvc5 failures print no counterexample values (
verification failed: u16mul [...] [backend=cvc5] [reason=counterexample]), in text or JSON.