File tree Expand file tree Collapse file tree 12 files changed +485
-191
lines changed
loop_guard_with_side_effects_fail
loop_guard_with_side_effects
nonvacuous_loop_contracts
variant_missing_invariant_warning
variant_multi_instruction_loop_head
src/goto-instrument/contracts Expand file tree Collapse file tree 12 files changed +485
-191
lines changed Original file line number Diff line number Diff line change 99^\[main\.\d+\] .* Check loop invariant before entry: SUCCESS$
1010^\[main\.\d+\] .* Check that loop invariant is preserved: SUCCESS$
1111^\[main\.\d+\] .* Check decreases clause on loop iteration: SUCCESS$
12- ^\[main.assigns.\d+] line 23 Check that s is assignable: SUCCESS$
13- ^\[main.assigns.\d+] line 24 Check that a is assignable: SUCCESS$
14- ^\[main.assigns.\d+] line 27 Check that s is assignable: SUCCESS$
12+ ^\[main.assigns.\d+] .* line 23 Check that s is assignable: SUCCESS$
13+ ^\[main.assigns.\d+] .* line 24 Check that a is assignable: SUCCESS$
14+ ^\[main.assigns.\d+] .* line 27 Check that s is assignable: SUCCESS$
1515^\[main\.assertion.\d+\] .* assertion s == n: SUCCESS$
1616^VERIFICATION SUCCESSFUL$
1717--
Original file line number Diff line number Diff line change 1+ #include <assert.h>
2+ #include <limits.h>
3+ #include <stdbool.h>
4+
5+ bool check (unsigned * i , unsigned * j , unsigned * k )
6+ {
7+ (* j )++ ;
8+ return * i < * k ;
9+ }
10+
11+ int main ()
12+ {
13+ unsigned i , j , k ;
14+ __CPROVER_assume (k < UINT_MAX );
15+
16+ i = j = 0 ;
17+
18+ while (check (& i , & j , & k ))
19+ // clang-format off
20+ __CPROVER_assigns (i , j )
21+ __CPROVER_loop_invariant (0 <= i && i == j && i <= k )
22+ // clang-format on
23+ {
24+ i ++ ;
25+ }
26+
27+ assert (i == k );
28+ assert (j == k + 1 );
29+ }
Original file line number Diff line number Diff line change 1+ CORE
2+ main.c
3+ --apply-loop-contracts _ --unsigned-overflow-check
4+ \[check.assigns\.\d+\] line \d+ Check that \*j is assignable: SUCCESS$
5+ \[check.overflow\.\d+\] line \d+ arithmetic overflow on unsigned \+ in \*j \+ 1u: SUCCESS
6+ \[check.overflow\.\d+\] line \d+ arithmetic overflow on unsigned \+ in \*j \+ 1u: SUCCESS
7+ \[check.assigns\.\d+\] line \d+ Check that return_value_check is assignable: SUCCESS$
8+ \[main\.\d+\] line \d+ Check loop invariant before entry: SUCCESS$
9+ \[main\.\d+\] line \d+ Check that loop invariant is preserved: SUCCESS$
10+ \[main.assigns\.\d+\] line \d+ Check that i is assignable: SUCCESS$
11+ \[main.assigns\.\d+\] line \d+ Check that j is assignable: SUCCESS$
12+ \[main.assigns\.\d+\] line \d+ Check that k is assignable: SUCCESS$
13+ \[main.assigns\.\d+\] line \d+ Check that i is valid: SUCCESS$
14+ \[main.assigns\.\d+\] line \d+ Check that j is valid: SUCCESS$
15+ \[main.assigns\.\d+\] line \d+ Check that i is assignable: SUCCESS$
16+ \[main.overflow\.\d+\] line \d+ arithmetic overflow on unsigned \+ in i \+ 1u: SUCCESS
17+ \[main.assertion\.\d+\] line \d+ assertion i == k: SUCCESS$
18+ \[main.overflow\.\d+\] line \d+ arithmetic overflow on unsigned \+ in k \+ \(unsigned int\)1: SUCCESS
19+ \[main.assertion\.\d+\] line \d+ assertion j == k \+ 1: SUCCESS$
20+ ^EXIT=0$
21+ ^SIGNAL=0$
22+ --
23+ --
24+ This test demonstrates a case where the loop guard has side effects.
25+ The loop contracts must specify the state of all modified variables,
26+ including those in the loop guard.
Original file line number Diff line number Diff line change 1+ #include <assert.h>
2+ #include <stdbool.h>
3+
4+ bool check (unsigned * i , unsigned * j , unsigned * k )
5+ {
6+ (* j )++ ;
7+ return * i < * k ;
8+ }
9+
10+ int main ()
11+ {
12+ unsigned i , j , k ;
13+
14+ i = j = 0 ;
15+
16+ while (check (& i , & j , & k ))
17+ // clang-format off
18+ __CPROVER_assigns (i )
19+ __CPROVER_loop_invariant (0 <= i && i <= k )
20+ // clang-format on
21+ {
22+ i ++ ;
23+ }
24+
25+ assert (i == k );
26+ }
Original file line number Diff line number Diff line change 1+ CORE
2+ main.c
3+ --apply-loop-contracts _ --unsigned-overflow-check
4+ \[check.assigns\.\d+\] line \d+ Check that \*j is assignable: FAILURE$
5+ \[check.assigns\.\d+\] line \d+ Check that return_value_check is assignable: SUCCESS$
6+ \[main\.\d+\] line \d+ Check loop invariant before entry: SUCCESS$
7+ \[main\.\d+\] line \d+ Check that loop invariant is preserved: SUCCESS$
8+ \[main.assigns\.\d+\] line \d+ Check that i is assignable: SUCCESS$
9+ \[main.assigns\.\d+\] line \d+ Check that j is assignable: SUCCESS$
10+ \[main.assigns\.\d+\] line \d+ Check that k is assignable: SUCCESS$
11+ \[main.assigns\.\d+\] line \d+ Check that i is valid: SUCCESS$
12+ \[main.assigns\.\d+\] line \d+ Check that i is assignable: SUCCESS$
13+ \[main.assertion\.\d+\] line \d+ assertion i == k: SUCCESS$
14+ ^EXIT=(6|10)$
15+ ^SIGNAL=0$
16+ --
17+ --
18+ This test demonstrates a case where the loop guard has side effects.
19+ The writes performed in the guard must also be specified
20+ in the assigns clause of the loop.
Original file line number Diff line number Diff line change 1+ #include <assert.h>
2+ #include <stdlib.h>
3+
4+ int main ()
5+ {
6+ size_t size ;
7+
8+ char * buf = malloc (size );
9+ char c ;
10+
11+ size_t start ;
12+ size_t end = start ;
13+
14+ while (end < size )
15+ // clang-format off
16+ __CPROVER_loop_invariant (start <= end && end <= size )
17+ __CPROVER_decreases (size - end )
18+ // clang-format on
19+ {
20+ if (buf [end ] != c )
21+ break ;
22+ end ++ ;
23+ }
24+
25+ if (start > size )
26+ {
27+ assert (end == start );
28+ }
29+ else
30+ {
31+ assert (start <= end && end <= size );
32+ }
33+ }
Original file line number Diff line number Diff line change 1+ CORE
2+ main.c
3+ --apply-loop-contracts _ --signed-overflow-check --unsigned-overflow-check
4+ \[main.\d+\] line \d+ Check loop invariant before entry: SUCCESS$
5+ \[main.\d+\] line \d+ Check that loop invariant is preserved: SUCCESS$
6+ \[main.assigns.\d+\] line \d+ Check that end is valid: SUCCESS$
7+ \[main.assigns.\d+\] line \d+ Check that end is assignable: SUCCESS$
8+ \[main.assertion.\d+\] line \d+ assertion end == start: SUCCESS$
9+ \[main.assertion.\d+\] line \d+ assertion start <= end && end <= size: SUCCESS$
10+ ^EXIT=0$
11+ ^SIGNAL=0$
12+ --
13+ --
14+ This test demonstrates a simplification that is now possible on loop contracts.
15+
16+ Prior to this commit, loop contracts were unconditionally applied on loops,
17+ and thus had to also consider the case when the loop doesn't run even once.
18+
19+ The contracts that were previously necessary were:
20+ __CPROVER_loop_invariant(
21+ (start > size && end == start) || (start <= end && end <= size)
22+ )
23+ __CPROVER_decreases(
24+ max(start, size) - end
25+ )
Original file line number Diff line number Diff line change 22main.c
33--apply-loop-contracts
44activate-multi-line-match
5- ^The loop at file main.c line 4 function main does not have an invariant.*.\nHence, a default invariant \('true'\) is being used to prove those .$
5+ ^The loop at file main.c line 4 function main does not have an invariant.*.\nHence, a default invariant \('true'\) is being used.* .$
66^\[main\.\d+\] .* Check loop invariant before entry: SUCCESS$
77^\[main\.\d+\] .* Check that loop invariant is preserved: SUCCESS$
88^\[main\.\d+\] .* Check decreases clause on loop iteration: SUCCESS$
Original file line number Diff line number Diff line change @@ -5,7 +5,7 @@ int main()
55
66 while (* y <= 0 && * y < 10 )
77 // clang-format off
8- __CPROVER_loop_invariant (1 == 1 )
8+ __CPROVER_loop_invariant (0 <= * y && * y <= 10 )
99 __CPROVER_decreases (10 - x )
1010 // clang-format on
1111 {
Original file line number Diff line number Diff line change 11CORE
22main.c
33--apply-loop-contracts
4- ^VERIFICATION FAILED$
5- ^EXIT=10$
4+ \[main\.\d+\] line \d+ Check loop invariant before entry: SUCCESS$
5+ \[main\.\d+\] line \d+ Check that loop invariant is preserved: SUCCESS$
6+ \[main\.\d+\] line \d+ Check decreases clause on loop iteration: SUCCESS$
7+ \[main\.\d+\] line \d+ Check that loop instrumentation was not truncated: SUCCESS$
8+ \[main\.assigns\.\d+\] line \d+ Check that x is valid: SUCCESS$
9+ \[main\.assigns\.\d+\] line \d+ Check that x is assignable: SUCCESS$
10+ ^VERIFICATION SUCCESSFUL$
11+ ^EXIT=0$
612^SIGNAL=0$
713--
814--
9- This test fails even without the fix proposed in the commit, so it should be improved.
10- It is expected to fail because the proposed invariant isn't strong enough to help prove
11- termination using the specified variant.
12-
13- The test highlights a case where a C loop guard is compiled to multiple GOTO instructions.
14- Therefore the loop_head pointer needs to be advanced multiple times to get to the loop body,
15- where the initial value of the loop variant (/ ranking function) must be recorded.
16-
17- The proposed fix advances the pointer until the source_location differs from the original
18- loop_head's source_location. However, this might still not work if the loop guard in the
19- original C code was split across multiple lines in the first place.
15+ This test checks that decreases clause is properly initialized
16+ when the loop head and loop invariant compilation emit several goto instructions.
You can’t perform that action at this time.
0 commit comments