-
Notifications
You must be signed in to change notification settings - Fork 274
CONTRACTS: Several fixes for loop contracts #6701
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
SaswatPadhi
merged 2 commits into
diffblue:develop
from
padhi-forks:loop-contracts-simplify
Mar 8, 2022
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
19 changes: 19 additions & 0 deletions
19
regression/contracts/loop_contracts_reject_overlapping_loops/main.c
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
#include <assert.h> | ||
|
||
int main() | ||
{ | ||
int i = 0, j = 0, k = 0; | ||
|
||
while(j < 10) | ||
{ | ||
while(k < 10) | ||
__CPROVER_loop_invariant(1 == 1) | ||
{ | ||
while(i < 10) | ||
{ | ||
i++; | ||
} | ||
} | ||
j++; | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
regression/contracts/loop_contracts_reject_overlapping_loops/test.desc
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
CORE | ||
main.c | ||
--apply-loop-contracts | ||
activate-multi-line-match | ||
Inner loop at: file main.c line 12 function main does not have contracts, but an enclosing loop does.\nPlease provide contracts for this loop, or unwind it first. | ||
^EXIT=(6|10)$ | ||
^SIGNAL=0$ | ||
-- | ||
-- | ||
This test checks that our instrumentation routines verify that inner loops | ||
either have contracts or are unwound, if any enclosing loop has contracts. |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
#include <assert.h> | ||
#include <limits.h> | ||
#include <stdbool.h> | ||
|
||
bool check(unsigned *i, unsigned *j, unsigned *k) | ||
{ | ||
(*j)++; | ||
return *i < *k; | ||
} | ||
|
||
int main() | ||
{ | ||
unsigned i, j, k; | ||
__CPROVER_assume(k < UINT_MAX); | ||
|
||
i = j = 0; | ||
|
||
while(check(&i, &j, &k)) | ||
// clang-format off | ||
__CPROVER_assigns(i, j) | ||
__CPROVER_loop_invariant(0 <= i && i == j && i <= k) | ||
// clang-format on | ||
{ | ||
i++; | ||
} | ||
|
||
assert(i == k); | ||
assert(j == k + 1); | ||
} |
26 changes: 26 additions & 0 deletions
26
regression/contracts/loop_guard_with_side_effects/test.desc
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
CORE | ||
main.c | ||
--apply-loop-contracts _ --unsigned-overflow-check | ||
\[check.assigns\.\d+\] line \d+ Check that \*j is assignable: SUCCESS$ | ||
\[check.overflow\.\d+\] line \d+ arithmetic overflow on unsigned \+ in \*j \+ 1u: SUCCESS | ||
\[check.overflow\.\d+\] line \d+ arithmetic overflow on unsigned \+ in \*j \+ 1u: SUCCESS | ||
\[check.assigns\.\d+\] line \d+ Check that return_value_check is assignable: SUCCESS$ | ||
\[main\.\d+\] line \d+ Check loop invariant before entry: SUCCESS$ | ||
\[main\.\d+\] line \d+ Check that loop invariant is preserved: SUCCESS$ | ||
\[main.assigns\.\d+\] line \d+ Check that i is assignable: SUCCESS$ | ||
\[main.assigns\.\d+\] line \d+ Check that j is assignable: SUCCESS$ | ||
\[main.assigns\.\d+\] line \d+ Check that k is assignable: SUCCESS$ | ||
\[main.assigns\.\d+\] line \d+ Check that i is valid: SUCCESS$ | ||
\[main.assigns\.\d+\] line \d+ Check that j is valid: SUCCESS$ | ||
\[main.assigns\.\d+\] line \d+ Check that i is assignable: SUCCESS$ | ||
\[main.overflow\.\d+\] line \d+ arithmetic overflow on unsigned \+ in i \+ 1u: SUCCESS | ||
\[main.assertion\.\d+\] line \d+ assertion i == k: SUCCESS$ | ||
\[main.overflow\.\d+\] line \d+ arithmetic overflow on unsigned \+ in k \+ \(unsigned int\)1: SUCCESS | ||
\[main.assertion\.\d+\] line \d+ assertion j == k \+ 1: SUCCESS$ | ||
^EXIT=0$ | ||
^SIGNAL=0$ | ||
-- | ||
-- | ||
This test demonstrates a case where the loop guard has side effects. | ||
The loop contracts must specify the state of all modified variables, | ||
including those in the loop guard. |
26 changes: 26 additions & 0 deletions
26
regression/contracts/loop_guard_with_side_effects_fail/main.c
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
#include <assert.h> | ||
#include <stdbool.h> | ||
|
||
bool check(unsigned *i, unsigned *j, unsigned *k) | ||
{ | ||
(*j)++; | ||
return *i < *k; | ||
} | ||
|
||
int main() | ||
{ | ||
unsigned i, j, k; | ||
|
||
i = j = 0; | ||
|
||
while(check(&i, &j, &k)) | ||
// clang-format off | ||
__CPROVER_assigns(i) | ||
__CPROVER_loop_invariant(0 <= i && i <= k) | ||
// clang-format on | ||
{ | ||
i++; | ||
} | ||
|
||
assert(i == k); | ||
} |
20 changes: 20 additions & 0 deletions
20
regression/contracts/loop_guard_with_side_effects_fail/test.desc
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
CORE | ||
main.c | ||
--apply-loop-contracts _ --unsigned-overflow-check | ||
\[check.assigns\.\d+\] line \d+ Check that \*j is assignable: FAILURE$ | ||
\[check.assigns\.\d+\] line \d+ Check that return_value_check is assignable: SUCCESS$ | ||
\[main\.\d+\] line \d+ Check loop invariant before entry: SUCCESS$ | ||
\[main\.\d+\] line \d+ Check that loop invariant is preserved: SUCCESS$ | ||
\[main.assigns\.\d+\] line \d+ Check that i is assignable: SUCCESS$ | ||
\[main.assigns\.\d+\] line \d+ Check that j is assignable: SUCCESS$ | ||
\[main.assigns\.\d+\] line \d+ Check that k is assignable: SUCCESS$ | ||
\[main.assigns\.\d+\] line \d+ Check that i is valid: SUCCESS$ | ||
\[main.assigns\.\d+\] line \d+ Check that i is assignable: SUCCESS$ | ||
\[main.assertion\.\d+\] line \d+ assertion i == k: SUCCESS$ | ||
^EXIT=(6|10)$ | ||
^SIGNAL=0$ | ||
-- | ||
-- | ||
This test demonstrates a case where the loop guard has side effects. | ||
The writes performed in the guard must also be specified | ||
in the assigns clause of the loop. |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
#include <assert.h> | ||
#include <stdlib.h> | ||
|
||
int main() | ||
{ | ||
size_t size; | ||
|
||
char *buf = malloc(size); | ||
char c; | ||
|
||
size_t start; | ||
size_t end = start; | ||
|
||
while(end < size) | ||
// clang-format off | ||
__CPROVER_loop_invariant(start <= end && end <= size) | ||
__CPROVER_decreases(size - end) | ||
// clang-format on | ||
{ | ||
if(buf[end] != c) | ||
break; | ||
end++; | ||
} | ||
|
||
if(start > size) | ||
{ | ||
assert(end == start); | ||
} | ||
else | ||
{ | ||
assert(start <= end && end <= size); | ||
} | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
CORE | ||
main.c | ||
--apply-loop-contracts _ --signed-overflow-check --unsigned-overflow-check | ||
\[main.\d+\] line \d+ Check loop invariant before entry: SUCCESS$ | ||
\[main.\d+\] line \d+ Check that loop invariant is preserved: SUCCESS$ | ||
\[main.assigns.\d+\] line \d+ Check that end is valid: SUCCESS$ | ||
\[main.assigns.\d+\] line \d+ Check that end is assignable: SUCCESS$ | ||
\[main.assertion.\d+\] line \d+ assertion end == start: SUCCESS$ | ||
\[main.assertion.\d+\] line \d+ assertion start <= end && end <= size: SUCCESS$ | ||
^EXIT=0$ | ||
^SIGNAL=0$ | ||
-- | ||
-- | ||
This test demonstrates a simplification that is now possible on loop contracts. | ||
|
||
Prior to this commit, loop contracts were unconditionally applied on loops, | ||
and thus had to also consider the case when the loop doesn't run even once. | ||
|
||
The contracts that were previously necessary were: | ||
__CPROVER_loop_invariant( | ||
(start > size && end == start) || (start <= end && end <= size) | ||
) | ||
__CPROVER_decreases( | ||
max(start, size) - end | ||
) |
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
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
23 changes: 10 additions & 13 deletions
23
regression/contracts/variant_multi_instruction_loop_head/test.desc
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,16 @@ | ||
CORE | ||
main.c | ||
--apply-loop-contracts | ||
^VERIFICATION FAILED$ | ||
^EXIT=10$ | ||
\[main\.\d+\] line \d+ Check loop invariant before entry: SUCCESS$ | ||
\[main\.\d+\] line \d+ Check that loop invariant is preserved: SUCCESS$ | ||
\[main\.\d+\] line \d+ Check decreases clause on loop iteration: SUCCESS$ | ||
\[main\.\d+\] line \d+ Check that loop instrumentation was not truncated: SUCCESS$ | ||
\[main\.assigns\.\d+\] line \d+ Check that x is valid: SUCCESS$ | ||
\[main\.assigns\.\d+\] line \d+ Check that x is assignable: SUCCESS$ | ||
^VERIFICATION SUCCESSFUL$ | ||
^EXIT=0$ | ||
^SIGNAL=0$ | ||
-- | ||
-- | ||
This test fails even without the fix proposed in the commit, so it should be improved. | ||
It is expected to fail because the proposed invariant isn't strong enough to help prove | ||
termination using the specified variant. | ||
|
||
The test highlights a case where a C loop guard is compiled to multiple GOTO instructions. | ||
Therefore the loop_head pointer needs to be advanced multiple times to get to the loop body, | ||
where the initial value of the loop variant (/ ranking function) must be recorded. | ||
|
||
The proposed fix advances the pointer until the source_location differs from the original | ||
loop_head's source_location. However, this might still not work if the loop guard in the | ||
original C code was split across multiple lines in the first place. | ||
This test checks that decreases clause is properly initialized | ||
when the loop head and loop invariant compilation emit several goto instructions. |
Oops, something went wrong.
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.
Uh oh!
There was an error while loading. Please reload this page.