Skip to content

Commit edeaf56

Browse files
Aren BabikianArenBabikian
Aren Babikian
authored andcommitted
Add support for quantifiers in function contracts
This adds basic support for quantifiers in funtion contracts. Current support only handles cases where a function contract contains a single, non-nested quantified formula.
1 parent 2459a7a commit edeaf56

File tree

27 files changed

+447
-2
lines changed

27 files changed

+447
-2
lines changed

regression/contracts/function_check_02/test.desc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
KNOWNBUG
1+
CORE
22
main.c
3-
--check-code-contracts
3+
--enforce-all-contracts
44
^EXIT=0$
55
^SIGNAL=0$
66
^VERIFICATION SUCCESSFUL$
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// clang-format off
2+
int f1(int *arr) __CPROVER_requires(__CPROVER_exists {
3+
int i;
4+
(0 <= i && i < 8) ==> arr[i] == 0
5+
}) __CPROVER_ensures(__CPROVER_exists {
6+
int i;
7+
(0 <= i && i < 8) ==> arr[i] == 0
8+
})
9+
// clang-format on
10+
{
11+
return 0;
12+
}
13+
14+
int main()
15+
{
16+
int arr[8];
17+
f1(arr);
18+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
CORE
2+
main.c
3+
--enforce-all-contracts
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
--
9+
The purpose of this test is to ensure that we can safely use __CPROVER_exists
10+
in a negative context (which is currently not always the case). By using the
11+
--enforce-all-contracts flag, this test assumes the statement in
12+
__CPROVER_requires, then asserts the same statement (in __CPROVER_ensures),
13+
thus, verification should be successful.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// clang-format off
2+
int f1(int *arr, int *len) __CPROVER_requires(__CPROVER_exists {
3+
int i;
4+
(0 <= i && i < len) ==> arr[i] == 0
5+
}) __CPROVER_ensures(__CPROVER_exists {
6+
int i;
7+
(0 <= i && i < len) ==> arr[i] == 0
8+
})
9+
// clang-format on
10+
{
11+
return 0;
12+
}
13+
14+
int main()
15+
{
16+
int len, arr[8];
17+
f1(arr, len);
18+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
KNOWNBUG
2+
main.c
3+
--enforce-all-contracts
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
--
9+
The purpose of this test is to ensure that we can safely use __CPROVER_exists
10+
in a negative context (which is currently not always the case). By using the
11+
--enforce-all-contracts flag, this test assumes the statement in
12+
__CPROVER_requires, then asserts the same statement (in __CPROVER_ensures),
13+
thus, verification should be successful.
14+
15+
Known bug:
16+
The current implementation cannot handle a structure such as
17+
__CPROVER_assume(__CPROVER_exists(int i; pred(i))), where i is
18+
not explicitly bounded to a predefined range (i.e. if at least
19+
one of its bound is only declared and not defined).
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// clang-format off
2+
int f1(int *arr) __CPROVER_ensures(__CPROVER_exists {
3+
int i;
4+
(0 <= i && i < 10) ==> arr[i] == i
5+
})
6+
// clang-format on
7+
{
8+
for(int i = 0; i < 10; i++)
9+
{
10+
arr[i] = i;
11+
}
12+
13+
return 0;
14+
}
15+
16+
int main()
17+
{
18+
int arr[10];
19+
f1(arr);
20+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
CORE
2+
main.c
3+
--enforce-all-contracts
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
--
9+
The purpose of this test is to ensure that we can safely use __CPROVER_exists
10+
in __CPROVER_ensures clauses. By using the --enforce-all-contracts flag,
11+
goto-instrument will transform the __CPROVER_ensures clauses into an
12+
assertion and the verification remains sound when using __CPROVER_exists.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// clang-format off
2+
int f1(int *arr) __CPROVER_ensures(__CPROVER_exists {
3+
int i;
4+
(0 <= i && i < 10) ==> arr[i] != 0
5+
})
6+
// clang-format on
7+
{
8+
for(int i = 0; i < 10; i++)
9+
{
10+
arr[i] = 0;
11+
}
12+
13+
return 0;
14+
}
15+
16+
int main()
17+
{
18+
int arr[10];
19+
f1(arr);
20+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
KNOWNBUG
2+
main.c
3+
--enforce-all-contracts
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
^VERIFICATION FAILED$
7+
--
8+
--
9+
The purpose of this test is to ensure that we can safely use __CPROVER_exists
10+
in __CPROVER_ensures clauses. By using the --enforce-all-contracts flag,
11+
goto-instrument will transform the __CPROVER_ensures clauses into an
12+
assertion and the verification remains sound when using __CPROVER_exists.
13+
14+
Known Bug:
15+
We expect verification to fail because arr[i] is always equal to 0 for
16+
[0 <= i < 10]. In fact, we expect the (0 <= i && i < 10) statement to act as a
17+
range for i. However, in the current implementation of quantifier handling,
18+
the (0 <= i && i < 10) statement is not interpreted as an explicit range, but
19+
instead, as part of a logic formula, which causes verification to succeed.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// clang-format off
2+
int f1(int *arr) __CPROVER_requires(__CPROVER_exists {
3+
int i;
4+
(0 <= i && i < 10) ==> arr[i] == 4
5+
}) __CPROVER_ensures(__CPROVER_return_value == 0)
6+
// clang-format on
7+
{
8+
return 0;
9+
}
10+
11+
int main()
12+
{
13+
int arr[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
14+
f1(arr);
15+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
CORE
2+
main.c
3+
--replace-all-calls-with-contracts
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
--
9+
The purpose of this test is to ensure that we can safely use __CPROVER_exists
10+
in __CPROVER_requires clauses. By using the --replace-all-calls-with-contracts
11+
flag, goto-instrument will transform the __CPROVER_requires clauses into an
12+
assertion and the verification remains sound when using __CPROVER_exists.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// clang-format off
2+
int f1(int *arr) __CPROVER_requires(__CPROVER_exists {
3+
int i;
4+
(0 <= i && i < 10) ==> arr[i] == 1
5+
}) __CPROVER_ensures(__CPROVER_return_value == 0)
6+
// clang-format on
7+
{
8+
return 0;
9+
}
10+
11+
int main()
12+
{
13+
int arr[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
14+
f1(arr);
15+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
KNOWNBUG
2+
main.c
3+
--replace-all-calls-with-contracts
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
^VERIFICATION FAILED$
7+
--
8+
--
9+
The purpose of this test is to ensure that we can safely use __CPROVER_exists
10+
in __CPROVER_requires clauses. By using the --replace-all-calls-with-contracts
11+
flag, goto-instrument will transform the __CPROVER_requires clauses into an
12+
assertion and the verification remains sound when using __CPROVER_exists.
13+
14+
Known Bug:
15+
We expect verification to fail because arr[i] is never equal to 1 for
16+
[0 <= i < 10]. In fact, we expect the (0 <= i && i < 10) statement to act as a
17+
range for i. However, in the current implementation of quantifier handling,
18+
the (0 <= i && i < 10) statement is not interpreted as an explicit range, but
19+
instead, as part of a logic formula, which causes verification to succeed.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// clang-format off
2+
int f1(int *arr) __CPROVER_requires(__CPROVER_forall {
3+
int i;
4+
(0 <= i && i < 8) ==> arr[i] == 0
5+
}) __CPROVER_ensures(__CPROVER_forall {
6+
int i;
7+
(0 <= i && i < 8) ==> arr[i] == 0
8+
})
9+
// clang-format on
10+
{
11+
return 0;
12+
}
13+
14+
int main()
15+
{
16+
int arr[8];
17+
f1(arr);
18+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
CORE
2+
main.c
3+
--enforce-all-contracts
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
--
9+
The purpose of this test is to ensure that we can safely use __CPROVER_forall
10+
in a negative context (which is currently not always the case). By using the
11+
--enforce-all-contracts flag, this test assumes the statement in
12+
__CPROVER_requires, then asserts the same statement (in __CPROVER_ensures),
13+
thus, verification should be successful.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// clang-format off
2+
int f1(int *arr, int len) __CPROVER_requires(__CPROVER_forall {
3+
int i;
4+
(0 <= i && i < len) ==> arr[i] == 0
5+
}) __CPROVER_ensures(__CPROVER_forall {
6+
int i;
7+
(0 <= i && i < len) ==> arr[i] == 0
8+
})
9+
// clang-format on
10+
{
11+
return 0;
12+
}
13+
14+
int main()
15+
{
16+
int len, arr[8];
17+
f1(arr, len);
18+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
KNOWNBUG
2+
main.c
3+
--enforce-all-contracts
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
--
9+
The purpose of this test is to ensure that we can safely use __CPROVER_forall
10+
in a negative context (which is currently not always the case). By using the
11+
--enforce-all-contracts flag, this test assumes the statement in
12+
__CPROVER_requires, then asserts the same statement (in __CPROVER_ensures),
13+
thus, verification should be successful.
14+
15+
Known bug:
16+
The current implementation cannot handle a structure such as
17+
__CPROVER_assume(__CPROVER_forall(int i; pred(i))), where i is
18+
not explicitly bounded to a predefined range (i.e. if at least
19+
one of its bound is only declared and not defined).
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// clang-format off
2+
int f1(int *arr) __CPROVER_ensures(__CPROVER_forall {
3+
int i;
4+
(0 <= i && i < 10) ==> arr[i] == 0
5+
})
6+
// clang-format on
7+
{
8+
for(int i = 0; i < 10; i++)
9+
{
10+
arr[i] = 0;
11+
}
12+
13+
return 0;
14+
}
15+
16+
int main()
17+
{
18+
int arr[10];
19+
f1(arr);
20+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
CORE
2+
main.c
3+
--enforce-all-contracts
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
--
9+
The purpose of this test is to ensure that we can safely use __CPROVER_forall
10+
in __CPROVER_ensures clauses. By using the --enforce-all-contracts
11+
flag, goto-instrument will transform the __CPROVER_ensures clauses into an
12+
assertion and the verification remains sound when using __CPROVER_forall.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// clang-format off
2+
int f1(int *arr) __CPROVER_ensures(__CPROVER_forall {
3+
int i;
4+
(0 <= i && i < 10) ==> arr[i] == i
5+
})
6+
// clang-format on
7+
{
8+
for(int i = 0; i < 10; i++)
9+
{
10+
if(i == 0)
11+
arr[i] = -1;
12+
else
13+
arr[i] = i;
14+
}
15+
16+
return 0;
17+
}
18+
19+
int main()
20+
{
21+
int arr[10];
22+
f1(arr);
23+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
CORE
2+
main.c
3+
--enforce-all-contracts
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
^VERIFICATION FAILED$
7+
--
8+
--
9+
The purpose of this test is to ensure that we can safely use __CPROVER_forall
10+
in __CPROVER_ensures clauses. By using the --enforce-all-contracts
11+
flag, goto-instrument will transform the __CPROVER_ensures clauses into an
12+
assertion and the verification remains sound when using __CPROVER_forall.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// clang-format off
2+
int f1(int *arr) __CPROVER_requires(__CPROVER_forall {
3+
int i;
4+
(0 <= i && i < 10) ==> arr[i] == i
5+
}) __CPROVER_ensures(__CPROVER_return_value == 0)
6+
// clang-format on
7+
{
8+
return 0;
9+
}
10+
11+
int main()
12+
{
13+
int arr[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
14+
f1(arr);
15+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
CORE
2+
main.c
3+
--replace-all-calls-with-contracts
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
--
9+
The purpose of this test is to ensure that we can safely use __CPROVER_forall
10+
in __CPROVER_requires clauses. By using the --replace-all-calls-with-contracts
11+
flag, goto-instrument will transform the __CPROVER_requires clauses into an
12+
assertion and the verification remains sound when using __CPROVER_forall.

0 commit comments

Comments
 (0)