File tree 8 files changed +411
-169
lines changed
loop_guard_with_side_effects
loop_guard_with_side_effects_fail
nonvacuous_loop_contracts
variant_missing_invariant_warning
src/goto-instrument/contracts 8 files changed +411
-169
lines changed 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
+ #define MAX_SIZE 1000000
5
+
6
+ int main ()
7
+ {
8
+ size_t size ;
9
+ __CPROVER_assume (size <= MAX_SIZE );
10
+
11
+ char * buf = malloc (size );
12
+ char c ;
13
+
14
+ size_t start ;
15
+ size_t end = start ;
16
+
17
+ while (end < size )
18
+ // clang-format off
19
+ __CPROVER_loop_invariant (start <= end && end <= size )
20
+ __CPROVER_decreases (size - end )
21
+ // clang-format on
22
+ {
23
+ if (buf [end ] != c )
24
+ break ;
25
+ end ++ ;
26
+ }
27
+
28
+ if (start > size )
29
+ {
30
+ assert (end == start );
31
+ }
32
+ else
33
+ {
34
+ assert (start <= end && end <= size );
35
+ }
36
+ }
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 2
2
main.c
3
3
--apply-loop-contracts
4
4
activate-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.* .$
6
6
^\[main\.\d+\] .* Check loop invariant before entry: SUCCESS$
7
7
^\[main\.\d+\] .* Check that loop invariant is preserved: SUCCESS$
8
8
^\[main\.\d+\] .* Check decreases clause on loop iteration: SUCCESS$
You can’t perform that action at this time.
0 commit comments