Skip to content

Commit 8e11d30

Browse files
committed
Migrate loop contracts regressions to dfcc
1 parent 8d491f3 commit 8e11d30

File tree

143 files changed

+3233
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

143 files changed

+3233
-0
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#include <assert.h>
2+
#include <stdlib.h>
3+
4+
static int adder(const int *a, const int *b)
5+
{
6+
return (*a + *b);
7+
}
8+
9+
int main()
10+
{
11+
int x = 1024;
12+
13+
int (*local_adder)(const int *, const int *) = adder;
14+
15+
while(x > 0)
16+
__CPROVER_loop_invariant(1 == 1)
17+
{
18+
x += local_adder(&x, &x); // loop detection fails
19+
//x += adder(&x, &x); // works fine
20+
}
21+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
CORE
2+
main.c
3+
--dfcc main --apply-loop-contracts
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
^\[main.\d+\] line \d+ Check loop invariant before entry: SUCCESS$
8+
^\[main.\d+\] line \d+ Check that loop invariant is preserved: SUCCESS$
9+
--
10+
--
11+
This is guarding against an issue described in https://github.com/diffblue/cbmc/issues/6168.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#include <assert.h>
2+
3+
int main()
4+
{
5+
int i, n, x[10];
6+
__CPROVER_assume(x[0] == x[9]);
7+
while(i < n)
8+
__CPROVER_loop_invariant(x[0] == __CPROVER_loop_entry(x[0]))
9+
{
10+
x[0] = x[9] - 1;
11+
x[0]++;
12+
}
13+
assert(x[0] == x[9]);
14+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
main.c
3+
--dfcc main --apply-loop-contracts
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
^Tracking history of index expressions is not supported yet\.
9+
--
10+
This test checks that `ID_index` expressions are allowed within history variables.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#include <assert.h>
2+
3+
int foo(int x)
4+
{
5+
return x;
6+
}
7+
8+
int main()
9+
{
10+
int i, n, x[10];
11+
__CPROVER_assume(x[0] == x[9]);
12+
while(i < n)
13+
__CPROVER_loop_invariant(x[0] == __CPROVER_loop_entry(foo(x[0])))
14+
{
15+
x[0] = x[9] - 1;
16+
x[0]++;
17+
}
18+
assert(x[0] == x[9]);
19+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
CORE
2+
main.c
3+
--dfcc --apply-loop-contracts
4+
^main.c.* error: Tracking history of side_effect expressions is not supported yet.$
5+
^CONVERSION ERROR$
6+
^EXIT=(1|64)$
7+
^SIGNAL=0$
8+
--
9+
--
10+
This test ensures that expressions with side effect, such as function calls,
11+
may not be used in history variables.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#include <assert.h>
2+
3+
int main()
4+
{
5+
while(1 == 1)
6+
__CPROVER_assigns() __CPROVER_loop_invariant(1 == 1)
7+
{
8+
}
9+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
CORE
2+
main.c
3+
--dfcc main --apply-loop-contracts
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^\[main.\d+\] .* Check loop invariant before entry: SUCCESS$
7+
^\[main.\d+\] .* Check that loop invariant is preserved: SUCCESS$
8+
^VERIFICATION SUCCESSFUL$
9+
--
10+
--
11+
This test checks that empty assigns clause is supported
12+
in loop contracts.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#include <assert.h>
2+
3+
int main()
4+
{
5+
int r;
6+
__CPROVER_assume(r >= 0);
7+
8+
while(r > 0)
9+
__CPROVER_loop_invariant(r >= 0)
10+
{
11+
--r;
12+
if(r <= 1)
13+
{
14+
break;
15+
}
16+
else
17+
{
18+
--r;
19+
}
20+
}
21+
22+
assert(r == 0);
23+
24+
return 0;
25+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
CORE
2+
main.c
3+
--dfcc main --apply-loop-contracts
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
^\[main\.\d+\] .* Check loop invariant before entry: SUCCESS$
7+
^\[main\.\d+\] .* Check that loop invariant is preserved: SUCCESS$
8+
^\[main.assigns.\d+\] .* Check that r is assignable: SUCCESS$
9+
^\[main\.assertion\.\d+\] .* assertion r == 0: FAILURE$
10+
^VERIFICATION FAILED$
11+
--
12+
This test is expected to fail along the code path where r is an even integer
13+
before entering the loop.
14+
The program is simply incompatible with the desired property in this case --
15+
there is no loop invariant that can establish the required assertion.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#include <assert.h>
2+
3+
int main()
4+
{
5+
int r;
6+
__CPROVER_assume(r >= 0);
7+
8+
while(r > 0)
9+
// clang-format off
10+
__CPROVER_loop_invariant(r >= 0)
11+
__CPROVER_decreases(r)
12+
// clang-format on
13+
{
14+
--r;
15+
if(r <= 1)
16+
{
17+
break;
18+
}
19+
else
20+
{
21+
--r;
22+
}
23+
}
24+
25+
assert(r == 0 || r == 1);
26+
27+
return 0;
28+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
CORE
2+
main.c
3+
--dfcc main --apply-loop-contracts
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^\[main\.\d+\] .* Check loop invariant before entry: SUCCESS$
7+
^\[main\.\d+\] .* Check that loop invariant is preserved: SUCCESS$
8+
^\[main.assigns.\d+\] .* Check that r is assignable: SUCCESS$
9+
^\[main\.assertion\.\d+\] .* assertion r == 0 || r == 1: SUCCESS$
10+
^VERIFICATION SUCCESSFUL$
11+
--
12+
This test checks that conditionals and `break` are correctly handled.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#include <assert.h>
2+
3+
int main()
4+
{
5+
int r;
6+
__CPROVER_assume(r >= 0);
7+
8+
while(r > 0)
9+
// clang-format off
10+
__CPROVER_loop_invariant(r >= 0)
11+
__CPROVER_decreases(r)
12+
// clang-format on
13+
{
14+
--r;
15+
if(r < 5)
16+
{
17+
continue;
18+
}
19+
else
20+
{
21+
--r;
22+
}
23+
}
24+
25+
assert(r == 0);
26+
27+
return 0;
28+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
CORE
2+
main.c
3+
--dfcc main --apply-loop-contracts
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^\[main\.\d+\] .* Check loop invariant before entry: SUCCESS$
7+
^\[main\.\d+\] .* Check that loop invariant is preserved: SUCCESS$
8+
^\[main.assigns.\d+\] .* Check that r is assignable: SUCCESS$
9+
^\[main\.assertion\.\d+\] .* assertion r == 0: SUCCESS$
10+
^VERIFICATION SUCCESSFUL$
11+
--
12+
This test checks that conditionals and `continue` are correctly handled.
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
#include <assert.h>
2+
3+
void swap(int *a, int *b)
4+
{
5+
*a ^= *b;
6+
*b ^= *a;
7+
*a ^= *b;
8+
}
9+
10+
int main()
11+
{
12+
int arr0, arr1, arr2, arr3, arr4;
13+
arr0 = 1;
14+
arr1 = 2;
15+
arr2 = 0;
16+
arr3 = 4;
17+
arr4 = 3;
18+
int *arr[5] = {&arr0, &arr1, &arr2, &arr3, &arr4};
19+
int pivot = 2;
20+
21+
int h = 5 - 1;
22+
int l = 0;
23+
int r = 1;
24+
while(h > l)
25+
// clang-format off
26+
__CPROVER_assigns(arr0, arr1, arr2, arr3, arr4, h, l, r)
27+
__CPROVER_loop_invariant(
28+
// Turn off `clang-format` because it breaks the `==>` operator.
29+
h >= l &&
30+
0 <= l && l < 5 &&
31+
0 <= h && h < 5 &&
32+
l <= r && r <= h &&
33+
(r == 0 ==> arr0 == pivot) &&
34+
(r == 1 ==> arr1 == pivot) &&
35+
(r == 2 ==> arr2 == pivot) &&
36+
(r == 3 ==> arr3 == pivot) &&
37+
(r == 4 ==> arr4 == pivot) &&
38+
(0 < l ==> arr0 <= pivot) &&
39+
(1 < l ==> arr1 <= pivot) &&
40+
(2 < l ==> arr2 <= pivot) &&
41+
(3 < l ==> arr3 <= pivot) &&
42+
(4 < l ==> arr4 <= pivot) &&
43+
(0 > h ==> arr0 >= pivot) &&
44+
(1 > h ==> arr1 >= pivot) &&
45+
(2 > h ==> arr2 >= pivot) &&
46+
(3 > h ==> arr3 >= pivot) &&
47+
(4 > h ==> arr4 >= pivot)
48+
)
49+
__CPROVER_decreases(h - l)
50+
// clang-format on
51+
{
52+
if(*(arr[h]) <= pivot && *(arr[l]) >= pivot)
53+
{
54+
swap(arr[h], arr[l]);
55+
if(r == h)
56+
{
57+
r = l;
58+
h--;
59+
}
60+
else if(r == l)
61+
{
62+
r = h;
63+
l++;
64+
}
65+
else
66+
{
67+
h--;
68+
l++;
69+
}
70+
}
71+
else if(*(arr[h]) <= pivot)
72+
{
73+
l++;
74+
}
75+
else
76+
{
77+
h--;
78+
}
79+
}
80+
81+
// Turn off `clang-format` because it breaks the `==>` operator.
82+
/* clang-format off */
83+
assert(0 <= r && r < 5);
84+
assert(*(arr[r]) == pivot);
85+
assert(0 < r ==> arr0 <= pivot);
86+
assert(1 < r ==> arr1 <= pivot);
87+
assert(2 < r ==> arr2 <= pivot);
88+
assert(3 < r ==> arr3 <= pivot);
89+
assert(4 < r ==> arr4 <= pivot);
90+
assert(0 > r ==> arr0 >= pivot);
91+
assert(1 > r ==> arr1 >= pivot);
92+
assert(2 > r ==> arr2 >= pivot);
93+
assert(3 > r ==> arr3 >= pivot);
94+
assert(4 > r ==> arr4 >= pivot);
95+
/* clang-format on */
96+
97+
return r;
98+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
CORE
2+
main.c
3+
--dfcc main --apply-loop-contracts
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^\[main.1\] .* Check loop invariant before entry: SUCCESS$
7+
^\[main.\d+\] .* Check that loop invariant is preserved: SUCCESS$
8+
^\[main.assertion.1\] .* assertion 0 <= r && r < 5: SUCCESS$
9+
^\[main.assertion.2\] .* assertion \*\(arr\[r\]\) == pivot: SUCCESS$
10+
^\[main.assertion.3\] .* assertion 0 < r ==> arr0 <= pivot: SUCCESS$
11+
^\[main.assertion.4\] .* assertion 1 < r ==> arr1 <= pivot: SUCCESS$
12+
^\[main.assertion.5\] .* assertion 2 < r ==> arr2 <= pivot: SUCCESS$
13+
^\[main.assertion.6\] .* assertion 3 < r ==> arr3 <= pivot: SUCCESS$
14+
^\[main.assertion.7\] .* assertion 4 < r ==> arr4 <= pivot: SUCCESS$
15+
^\[main.assertion.8\] .* assertion 0 > r ==> arr0 >= pivot: SUCCESS$
16+
^\[main.assertion.9\] .* assertion 1 > r ==> arr1 >= pivot: SUCCESS$
17+
^\[main.assertion.10\] .* assertion 2 > r ==> arr2 >= pivot: SUCCESS$
18+
^\[main.assertion.11\] .* assertion 3 > r ==> arr3 >= pivot: SUCCESS$
19+
^\[main.assertion.12\] .* assertion 4 > r ==> arr4 >= pivot: SUCCESS$
20+
^VERIFICATION SUCCESSFUL$
21+
--
22+
This test checks the invariant contracts on a larger problem --- in this case,
23+
the partition function of quicksort, applied to a fixed-length array.
24+
This serves as a stop-gap test until issues to do with quantifiers and
25+
side-effects in loop invariants are fixed.
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#include <assert.h>
2+
3+
int main()
4+
{
5+
int r, n, x, y;
6+
__CPROVER_assume(n > 0 && x == y);
7+
8+
for(r = 0; r < n; ++r)
9+
// clang-format off
10+
__CPROVER_loop_invariant(0 <= r && r <= n)
11+
__CPROVER_loop_invariant(x == y + r)
12+
__CPROVER_decreases(n - r)
13+
// clang-format on
14+
{
15+
x++;
16+
}
17+
while(r > 0)
18+
// clang-format off
19+
__CPROVER_loop_invariant(r >= 0 && x == y + n + (n - r))
20+
__CPROVER_decreases(r)
21+
// clang-format on
22+
{
23+
y--;
24+
r--;
25+
}
26+
27+
assert(x == y + 2 * n);
28+
29+
return 0;
30+
}

0 commit comments

Comments
 (0)