Skip to content

Supports quantifiers in function contracts #5959

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions regression/contracts/function_check_02/test.desc
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
KNOWNBUG
CORE
main.c
--check-code-contracts
--enforce-all-contracts
^EXIT=0$
^SIGNAL=0$
^VERIFICATION SUCCESSFUL$
Expand Down
18 changes: 18 additions & 0 deletions regression/contracts/quantifiers-exists-both-01/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// clang-format off
int f1(int *arr) __CPROVER_requires(__CPROVER_exists {
int i;
(0 <= i && i < 8) ==> arr[i] == 0
}) __CPROVER_ensures(__CPROVER_exists {
int i;
(0 <= i && i < 8) ==> arr[i] == 0
})
// clang-format on
{
return 0;
}

int main()
{
int arr[8];
f1(arr);
}
13 changes: 13 additions & 0 deletions regression/contracts/quantifiers-exists-both-01/test.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
CORE
main.c
--enforce-all-contracts
^EXIT=0$
^SIGNAL=0$
^VERIFICATION SUCCESSFUL$
--
--
The purpose of this test is to ensure that we can safely use __CPROVER_exists
in a negative context (which is currently not always the case). By using the
--enforce-all-contracts flag, this test assumes the statement in
__CPROVER_requires, then asserts the same statement (in __CPROVER_ensures),
thus, verification should be successful.
18 changes: 18 additions & 0 deletions regression/contracts/quantifiers-exists-both-02/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// clang-format off
int f1(int *arr, int *len) __CPROVER_requires(__CPROVER_exists {
int i;
(0 <= i && i < len) ==> arr[i] == 0
}) __CPROVER_ensures(__CPROVER_exists {
int i;
(0 <= i && i < len) ==> arr[i] == 0
})
// clang-format on
{
return 0;
}

int main()
{
int len, arr[8];
f1(arr, len);
}
19 changes: 19 additions & 0 deletions regression/contracts/quantifiers-exists-both-02/test.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
KNOWNBUG
main.c
--enforce-all-contracts
^EXIT=0$
^SIGNAL=0$
^VERIFICATION SUCCESSFUL$
--
--
The purpose of this test is to ensure that we can safely use __CPROVER_exists
in a negative context (which is currently not always the case). By using the
--enforce-all-contracts flag, this test assumes the statement in
__CPROVER_requires, then asserts the same statement (in __CPROVER_ensures),
thus, verification should be successful.

Known bug:
The current implementation cannot handle a structure such as
__CPROVER_assume(__CPROVER_exists(int i; pred(i))), where i is
not explicitly bounded to a predefined range (i.e. if at least
one of its bound is only declared and not defined).
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you tried the SMT back-end?

20 changes: 20 additions & 0 deletions regression/contracts/quantifiers-exists-ensures-01/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// clang-format off
int f1(int *arr) __CPROVER_ensures(__CPROVER_exists {
int i;
(0 <= i && i < 10) ==> arr[i] == i
})
// clang-format on
{
for(int i = 0; i < 10; i++)
{
arr[i] = i;
}

return 0;
}

int main()
{
int arr[10];
f1(arr);
}
12 changes: 12 additions & 0 deletions regression/contracts/quantifiers-exists-ensures-01/test.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
CORE
main.c
--enforce-all-contracts
^EXIT=0$
^SIGNAL=0$
^VERIFICATION SUCCESSFUL$
--
--
The purpose of this test is to ensure that we can safely use __CPROVER_exists
in __CPROVER_ensures clauses. By using the --enforce-all-contracts flag,
goto-instrument will transform the __CPROVER_ensures clauses into an
assertion and the verification remains sound when using __CPROVER_exists.
20 changes: 20 additions & 0 deletions regression/contracts/quantifiers-exists-ensures-02/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// clang-format off
int f1(int *arr) __CPROVER_ensures(__CPROVER_exists {
int i;
(0 <= i && i < 10) ==> arr[i] != 0
})
// clang-format on
{
for(int i = 0; i < 10; i++)
{
arr[i] = 0;
}

return 0;
}

int main()
{
int arr[10];
f1(arr);
}
19 changes: 19 additions & 0 deletions regression/contracts/quantifiers-exists-ensures-02/test.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
KNOWNBUG
main.c
--enforce-all-contracts
^EXIT=10$
^SIGNAL=0$
^VERIFICATION FAILED$
--
--
The purpose of this test is to ensure that we can safely use __CPROVER_exists
in __CPROVER_ensures clauses. By using the --enforce-all-contracts flag,
goto-instrument will transform the __CPROVER_ensures clauses into an
assertion and the verification remains sound when using __CPROVER_exists.

Known Bug:
We expect verification to fail because arr[i] is always equal to 0 for
[0 <= i < 10]. In fact, we expect the (0 <= i && i < 10) statement to act as a
range for i. However, in the current implementation of quantifier handling,
the (0 <= i && i < 10) statement is not interpreted as an explicit range, but
instead, as part of a logic formula, which causes verification to succeed.
15 changes: 15 additions & 0 deletions regression/contracts/quantifiers-exists-requires-01/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// clang-format off
int f1(int *arr) __CPROVER_requires(__CPROVER_exists {
int i;
(0 <= i && i < 10) ==> arr[i] == 4
}) __CPROVER_ensures(__CPROVER_return_value == 0)
// clang-format on
{
return 0;
}

int main()
{
int arr[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
f1(arr);
}
12 changes: 12 additions & 0 deletions regression/contracts/quantifiers-exists-requires-01/test.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
CORE
main.c
--replace-all-calls-with-contracts
^EXIT=0$
^SIGNAL=0$
^VERIFICATION SUCCESSFUL$
--
--
The purpose of this test is to ensure that we can safely use __CPROVER_exists
in __CPROVER_requires clauses. By using the --replace-all-calls-with-contracts
flag, goto-instrument will transform the __CPROVER_requires clauses into an
assertion and the verification remains sound when using __CPROVER_exists.
15 changes: 15 additions & 0 deletions regression/contracts/quantifiers-exists-requires-02/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// clang-format off
int f1(int *arr) __CPROVER_requires(__CPROVER_exists {
int i;
(0 <= i && i < 10) ==> arr[i] == 1
}) __CPROVER_ensures(__CPROVER_return_value == 0)
// clang-format on
{
return 0;
}

int main()
{
int arr[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
f1(arr);
}
19 changes: 19 additions & 0 deletions regression/contracts/quantifiers-exists-requires-02/test.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
KNOWNBUG
main.c
--replace-all-calls-with-contracts
^EXIT=10$
^SIGNAL=0$
^VERIFICATION FAILED$
--
--
The purpose of this test is to ensure that we can safely use __CPROVER_exists
in __CPROVER_requires clauses. By using the --replace-all-calls-with-contracts
flag, goto-instrument will transform the __CPROVER_requires clauses into an
assertion and the verification remains sound when using __CPROVER_exists.

Known Bug:
We expect verification to fail because arr[i] is never equal to 1 for
[0 <= i < 10]. In fact, we expect the (0 <= i && i < 10) statement to act as a
range for i. However, in the current implementation of quantifier handling,
the (0 <= i && i < 10) statement is not interpreted as an explicit range, but
instead, as part of a logic formula, which causes verification to succeed.
18 changes: 18 additions & 0 deletions regression/contracts/quantifiers-forall-both-01/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// clang-format off
int f1(int *arr) __CPROVER_requires(__CPROVER_forall {
int i;
(0 <= i && i < 8) ==> arr[i] == 0
}) __CPROVER_ensures(__CPROVER_forall {
int i;
(0 <= i && i < 8) ==> arr[i] == 0
})
// clang-format on
{
return 0;
}

int main()
{
int arr[8];
f1(arr);
}
13 changes: 13 additions & 0 deletions regression/contracts/quantifiers-forall-both-01/test.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
CORE
main.c
--enforce-all-contracts
^EXIT=0$
^SIGNAL=0$
^VERIFICATION SUCCESSFUL$
--
--
The purpose of this test is to ensure that we can safely use __CPROVER_forall
in a negative context (which is currently not always the case). By using the
--enforce-all-contracts flag, this test assumes the statement in
__CPROVER_requires, then asserts the same statement (in __CPROVER_ensures),
thus, verification should be successful.
18 changes: 18 additions & 0 deletions regression/contracts/quantifiers-forall-both-02/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// clang-format off
int f1(int *arr, int len) __CPROVER_requires(__CPROVER_forall {
int i;
(0 <= i && i < len) ==> arr[i] == 0
}) __CPROVER_ensures(__CPROVER_forall {
int i;
(0 <= i && i < len) ==> arr[i] == 0
})
// clang-format on
{
return 0;
}

int main()
{
int len, arr[8];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think len should also be initialized (to 8).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Such a case is already tested for in the quantifiers-forall-both-01 test, and it works with the current implementation. The purpose of this test is in fact to check wether CBMC can handle cases where the range of the quantified variable is not explicitly set a priori.

f1(arr, len);
}
19 changes: 19 additions & 0 deletions regression/contracts/quantifiers-forall-both-02/test.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
KNOWNBUG
main.c
--enforce-all-contracts
^EXIT=0$
^SIGNAL=0$
^VERIFICATION SUCCESSFUL$
--
--
The purpose of this test is to ensure that we can safely use __CPROVER_forall
in a negative context (which is currently not always the case). By using the
--enforce-all-contracts flag, this test assumes the statement in
__CPROVER_requires, then asserts the same statement (in __CPROVER_ensures),
thus, verification should be successful.

Known bug:
The current implementation cannot handle a structure such as
__CPROVER_assume(__CPROVER_forall(int i; pred(i))), where i is
not explicitly bounded to a predefined range (i.e. if at least
one of its bound is only declared and not defined).
20 changes: 20 additions & 0 deletions regression/contracts/quantifiers-forall-ensures-01/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// clang-format off
int f1(int *arr) __CPROVER_ensures(__CPROVER_forall {
int i;
(0 <= i && i < 10) ==> arr[i] == 0
})
// clang-format on
{
for(int i = 0; i < 10; i++)
{
arr[i] = 0;
}

return 0;
}

int main()
{
int arr[10];
f1(arr);
}
12 changes: 12 additions & 0 deletions regression/contracts/quantifiers-forall-ensures-01/test.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
CORE
main.c
--enforce-all-contracts
^EXIT=0$
^SIGNAL=0$
^VERIFICATION SUCCESSFUL$
--
--
The purpose of this test is to ensure that we can safely use __CPROVER_forall
in __CPROVER_ensures clauses. By using the --enforce-all-contracts
flag, goto-instrument will transform the __CPROVER_ensures clauses into an
assertion and the verification remains sound when using __CPROVER_forall.
23 changes: 23 additions & 0 deletions regression/contracts/quantifiers-forall-ensures-02/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// clang-format off
int f1(int *arr) __CPROVER_ensures(__CPROVER_forall {
int i;
(0 <= i && i < 10) ==> arr[i] == i
})
// clang-format on
{
for(int i = 0; i < 10; i++)
{
if(i == 0)
arr[i] = -1;
else
arr[i] = i;
}

return 0;
}

int main()
{
int arr[10];
f1(arr);
}
12 changes: 12 additions & 0 deletions regression/contracts/quantifiers-forall-ensures-02/test.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
CORE
main.c
--enforce-all-contracts
^EXIT=10$
^SIGNAL=0$
^VERIFICATION FAILED$
--
--
The purpose of this test is to ensure that we can safely use __CPROVER_forall
in __CPROVER_ensures clauses. By using the --enforce-all-contracts
flag, goto-instrument will transform the __CPROVER_ensures clauses into an
assertion and the verification remains sound when using __CPROVER_forall.
15 changes: 15 additions & 0 deletions regression/contracts/quantifiers-forall-requires-01/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// clang-format off
int f1(int *arr) __CPROVER_requires(__CPROVER_forall {
int i;
(0 <= i && i < 10) ==> arr[i] == i
}) __CPROVER_ensures(__CPROVER_return_value == 0)
// clang-format on
{
return 0;
}

int main()
{
int arr[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
f1(arr);
}
12 changes: 12 additions & 0 deletions regression/contracts/quantifiers-forall-requires-01/test.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
CORE
main.c
--replace-all-calls-with-contracts
^EXIT=0$
^SIGNAL=0$
^VERIFICATION SUCCESSFUL$
--
--
The purpose of this test is to ensure that we can safely use __CPROVER_forall
in __CPROVER_requires clauses. By using the --replace-all-calls-with-contracts
flag, goto-instrument will transform the __CPROVER_requires clauses into an
assertion and the verification remains sound when using __CPROVER_forall.
Loading