Skip to content

Commit 29b9e1e

Browse files
SaswatPadhiAalok Thakkar
andcommitted
Added loop_entry history variables for invariants
In this commit we introduce a new expression, `__CPROVER_loop_entry`, which can be used within loop invariants to track history of variables. `__CPROVER_loop_entry(x)` returns the initial value of a variable just before the very first iteration of a loop. Co-authored-by: Aalok Thakkar <[email protected]>
1 parent e4369b6 commit 29b9e1e

File tree

20 files changed

+244
-41
lines changed

20 files changed

+244
-41
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
void foo(int *x) __CPROVER_assigns(*x)
2+
__CPROVER_ensures(*x == __CPROVER_loop_entry(*x) + 5)
3+
{
4+
*x = *x + 5;
5+
}
6+
7+
int main()
8+
{
9+
int n;
10+
foo(&n);
11+
12+
return 0;
13+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
main.c
3+
--enforce-all-contracts
4+
^main.c.* error: __CPROVER_loop_entry is not allowed within postconditions.$
5+
^CONVERSION ERROR$
6+
^EXIT=(1|64)$
7+
^SIGNAL=0$
8+
--
9+
--
10+
This test ensures that __CPROVER_loop_entry cannot be used within ensures clause.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
void bar(int *x) __CPROVER_assigns(*x)
2+
__CPROVER_requires(*x == __CPROVER_loop_entry(*x) + 5)
3+
{
4+
*x = *x + 5;
5+
}
6+
7+
int main()
8+
{
9+
int n;
10+
foo(&n);
11+
12+
return 0;
13+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
main.c
3+
--enforce-all-contracts
4+
^main.c.* error: __CPROVER_loop_entry is not allowed within preconditions.$
5+
^CONVERSION ERROR$
6+
^EXIT=(1|64)$
7+
^SIGNAL=0$
8+
--
9+
--
10+
This test ensures that __CPROVER_loop_entry cannot be used within requires clause.
Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
CORE
22
main.c
33
--replace-all-calls-with-contracts
4+
^main.c.* error: __CPROVER_old is not allowed within preconditions.$
5+
^CONVERSION ERROR$
46
^EXIT=(1|64)$
57
^SIGNAL=0$
6-
^CONVERSION ERROR$
7-
error: __CPROVER_old expressions are not allowed in __CPROVER_requires clauses
88
--
99
--
10-
Verification:
1110
This test checks that history variables cannot be used as part of the
12-
pre-condition contract. In this case, verification should fail.
11+
pre-condition (requires) contract.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#include <assert.h>
2+
3+
void main()
4+
{
5+
int *x, y, z;
6+
7+
x = &z;
8+
9+
while(y > 0)
10+
__CPROVER_loop_invariant(*x == __CPROVER_old(*x))
11+
{
12+
--y;
13+
*x = *x + 1;
14+
*x = *x - 1;
15+
}
16+
assert(*x == z);
17+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
main.c
3+
--apply-loop-contracts
4+
^main.c.* error: __CPROVER_old is not allowed within loop invariants.$
5+
^CONVERSION ERROR$
6+
^EXIT=(1|64)$
7+
^SIGNAL=0$
8+
--
9+
--
10+
This test ensures that __CPROVER_old cannot be used within loop contracts.
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#include <assert.h>
2+
#include <stdlib.h>
3+
4+
typedef struct
5+
{
6+
int *n;
7+
} s;
8+
9+
void main()
10+
{
11+
int *x1, y1, z1;
12+
x1 = &z1;
13+
14+
while(y1 > 0)
15+
__CPROVER_loop_invariant(*x1 == __CPROVER_loop_entry(*x1))
16+
{
17+
--y1;
18+
*x1 = *x1 + 1;
19+
*x1 = *x1 - 1;
20+
}
21+
assert(*x1 == z1);
22+
23+
int x2, y2, z2;
24+
x2 = z2;
25+
26+
while(y2 > 0)
27+
__CPROVER_loop_invariant(x2 == __CPROVER_loop_entry(x2))
28+
{
29+
--y2;
30+
x2 = x2 + 1;
31+
x2 = x2 - 1;
32+
}
33+
assert(x2 == z2);
34+
35+
int y3;
36+
s *s1, *s2;
37+
s2->n = malloc(sizeof(int));
38+
s1->n = s2->n;
39+
40+
while(y3 > 0)
41+
__CPROVER_loop_invariant(s1->n == __CPROVER_loop_entry(s1->n))
42+
{
43+
--y3;
44+
s1->n = s1->n + 1;
45+
s1->n = s1->n - 1;
46+
}
47+
48+
assert(*(s1->n) == *(s2->n));
49+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
CORE
2+
main.c
3+
--apply-loop-contracts
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^\[main.1\] .* Check loop invariant before entry: SUCCESS$
7+
^\[main.2\] .* Check that loop invariant is preserved: SUCCESS$
8+
^\[main.assertion.1\] .* assertion \*x1 == z1: SUCCESS$
9+
^\[main.3\] .* Check loop invariant before entry: SUCCESS$
10+
^\[main.4\] .* Check that loop invariant is preserved: SUCCESS$
11+
^\[main.assertion.2\] .* assertion x2 == z2: SUCCESS$
12+
^\[main.5\] .* Check loop invariant before entry: SUCCESS$
13+
^\[main.6\] .* Check that loop invariant is preserved: SUCCESS$
14+
^\[main.assertion.3\] .* assertion \*\(s1->n\) == \*\(s2->n\): SUCCESS$
15+
^VERIFICATION SUCCESSFUL$
16+
--
17+
--
18+
This test checks that __CPROVER_loop_entry is supported.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#include <assert.h>
2+
3+
void main()
4+
{
5+
int x, y, z;
6+
x = z;
7+
8+
while(y > 0)
9+
__CPROVER_loop_invariant(x == __CPROVER_loop_entry(x))
10+
{
11+
--y;
12+
x = x + 1;
13+
x = x - 2;
14+
}
15+
}

0 commit comments

Comments
 (0)