Skip to content

Commit 66d9d17

Browse files
authored
Merge pull request #6012 from ArenBabikian/loop-quantifiers-temp
Allow quantifiers within loop invariants
2 parents c2f711b + 6993cf4 commit 66d9d17

File tree

9 files changed

+257
-71
lines changed

9 files changed

+257
-71
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#include <assert.h>
2+
3+
#define N 16
4+
5+
void main()
6+
{
7+
int a[N];
8+
a[10] = 0;
9+
10+
for(int i = 0; i < N; ++i)
11+
// clang-format off
12+
__CPROVER_loop_invariant(
13+
(0 <= i) && (i <= N) &&
14+
__CPROVER_forall {
15+
int k;
16+
// constant bounds for explicit unrolling with SAT backend
17+
(0 <= k && k <= N) ==> (
18+
// the actual symbolic bound for `k`
19+
k < i ==> a[k] == 1
20+
)
21+
}
22+
)
23+
// clang-format on
24+
{
25+
a[i] = 1;
26+
}
27+
28+
assert(a[10] == 1);
29+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
CORE
2+
main.c
3+
--enforce-all-contracts
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^\[main.1\] line .* Check loop invariant before entry: SUCCESS
7+
^\[main.2\] line .* Check that loop invariant is preserved: SUCCESS
8+
^\[main.assertion.1\] line .* assertion a\[10\] == 1: SUCCESS
9+
^VERIFICATION SUCCESSFUL$
10+
--
11+
--
12+
This test case checks the handling of a `forall` quantifier within a loop invariant.
13+
14+
This test case uses explicit constant bounds on the quantified variable,
15+
so that it can be unrolled (to conjunctions) with the SAT backend.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#include <assert.h>
2+
3+
void main()
4+
{
5+
int N, a[64];
6+
__CPROVER_assume(0 <= N && N < 64);
7+
8+
for(int i = 0; i < N; ++i)
9+
// clang-format off
10+
__CPROVER_loop_invariant(
11+
(0 <= i) && (i <= N) &&
12+
__CPROVER_forall {
13+
int k;
14+
(0 <= k && k < i) ==> a[k] == 1
15+
}
16+
)
17+
// clang-format on
18+
{
19+
a[i] = 1;
20+
}
21+
22+
// clang-format off
23+
assert(__CPROVER_forall {
24+
int k;
25+
(0 <= k && k < N) ==> a[k] == 1
26+
});
27+
// clang-format on
28+
29+
int k;
30+
__CPROVER_assume(0 <= k && k < N);
31+
assert(a[k] == 1);
32+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
KNOWNBUG smt-backend broken-cprover-smt-backend
2+
main.c
3+
--enforce-all-contracts
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^\[main.1\] line .* Check loop invariant before entry: SUCCESS
7+
^\[main.2\] line .* Check that loop invariant is preserved: SUCCESS
8+
^\[main.assertion.1\] line .* assertion .*: SUCCESS
9+
^VERIFICATION SUCCESSFUL$
10+
--
11+
--
12+
This test case checks the handling of a universal quantifier, with a symbolic
13+
upper bound, within a loop invariant.
14+
15+
The test is tagged:
16+
- `smt-backend`:
17+
because the SAT backend does not support (simply ignores) `forall` in negative (e.g. assume) contexts.
18+
- `broken-cprover-smt-backend`:
19+
because the CPROVER SMT2 solver cannot handle (errors out on) `forall` in negative (e.g. assume) contexts.
20+
21+
It has been tagged `KNOWNBUG` for now since `contracts` regression tests are not run with SMT backend yet.
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#include <assert.h>
2+
#include <stdlib.h>
3+
4+
#define MAX_SIZE 64
5+
6+
void main()
7+
{
8+
unsigned N;
9+
__CPROVER_assume(N <= MAX_SIZE);
10+
11+
int *a = malloc(N * sizeof(int));
12+
13+
for(int i = 0; i < N; ++i)
14+
// clang-format off
15+
__CPROVER_loop_invariant(
16+
(0 <= i) && (i <= N) &&
17+
(i != 0 ==> __CPROVER_exists {
18+
int k;
19+
// constant bounds for explicit unrolling with SAT backend
20+
(0 <= k && k <= MAX_SIZE) && (
21+
// the actual symbolic bound for `k`
22+
k < i && a[k] == 1
23+
)
24+
})
25+
)
26+
// clang-format on
27+
{
28+
a[i] = 1;
29+
}
30+
31+
// clang-format off
32+
assert(
33+
N != 0 ==> __CPROVER_exists {
34+
int k;
35+
// constant bounds for explicit unrolling with SAT backend
36+
(0 <= k && k <= MAX_SIZE) && (
37+
// the actual symbolic bound for `k`
38+
k < N && a[k] == 1
39+
)
40+
});
41+
// clang-format on
42+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
CORE
2+
main.c
3+
--enforce-all-contracts
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^\[main.1\] line .* Check loop invariant before entry: SUCCESS
7+
^\[main.2\] line .* Check that loop invariant is preserved: SUCCESS
8+
^\[main.assertion.1\] line .* assertion .*: SUCCESS
9+
^VERIFICATION SUCCESSFUL$
10+
--
11+
--
12+
This test case checks the handling of an existential quantifier, with a symbolic
13+
upper bound, within a loop invariant.
14+
15+
This test case uses explicit constant bounds on the quantified variable,
16+
so that it can be unrolled (to conjunctions) with the SAT backend.

0 commit comments

Comments
 (0)