Skip to content

Commit 5f37ed6

Browse files
committed
Support for empty assigns clause
CBMC currently doesn't enforce assigns clauses if there isn't one. However, whenever enforcing a function contract, the absence of an assigns clause should be interpreted as an empty write set (i.e., no inputs will be modified by this function). CBMC now properly checks for empty assigns clause behavior. Signed-off-by: Felipe R. Monteiro <[email protected]>
1 parent c41ce2b commit 5f37ed6

File tree

9 files changed

+66
-38
lines changed

9 files changed

+66
-38
lines changed
Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
CORE
22
main.c
33
--enforce-all-contracts
4-
^EXIT=10$
4+
^EXIT=0$
55
^SIGNAL=0$
6-
^VERIFICATION FAILED$
6+
^VERIFICATION SUCCESSFUL$
77
--
88
--
9-
This test checks that verification fails when a function with an assigns clause calls a function without an assigns clause.
9+
This test checks that verification succeeds when enforcing a contract
10+
for functions, without assigns clauses, that don't modify anything.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
int foo(int *x) __CPROVER_assigns(*x)
2+
__CPROVER_ensures(__CPROVER_return_value == *x + 5)
3+
{
4+
int z = 5;
5+
int y = bar(&z);
6+
return *x + 5;
7+
}
8+
9+
int bar(int *a) __CPROVER_ensures(__CPROVER_return_value >= 5)
10+
{
11+
*a = *a + 2;
12+
return *a;
13+
}
14+
15+
int main()
16+
{
17+
int n;
18+
n = foo(&n);
19+
return 0;
20+
}
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+
^EXIT=10$
5+
^SIGNAL=0$
6+
^VERIFICATION FAILED$
7+
--
8+
--
9+
Checks whether verification fails when enforcing a contract
10+
for functions, without assigns clauses, that modify an input.

regression/contracts/function_check_02/main.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,16 @@
44
// A known bug (resolved in PR #2278) causes the use of quantifiers
55
// in ensures to fail.
66

7+
// clang-format off
78
int initialize(int *arr)
9+
__CPROVER_assigns(*arr)
810
__CPROVER_ensures(
9-
__CPROVER_forall {int i; (0 <= i && i < 10) ==> arr[i] == i}
11+
__CPROVER_forall {
12+
int i;
13+
(0 <= i && i < 10) ==> arr[i] == i
14+
}
1015
)
16+
// clang-format on
1117
{
1218
for(int i = 0; i < 10; i++)
1319
{

regression/contracts/quantifiers-exists-ensures-01/main.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
// clang-format off
2-
int f1(int *arr) __CPROVER_ensures(__CPROVER_exists {
3-
int i;
4-
(0 <= i && i < 10) ==> arr[i] == i
5-
})
2+
int f1(int *arr)
3+
__CPROVER_assigns(*arr)
4+
__CPROVER_ensures(__CPROVER_exists {
5+
int i;
6+
(0 <= i && i < 10) ==> arr[i] == i
7+
})
68
// clang-format on
79
{
810
for(int i = 0; i < 10; i++)

regression/contracts/quantifiers-forall-ensures-01/main.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
// clang-format off
2-
int f1(int *arr) __CPROVER_ensures(__CPROVER_forall {
3-
int i;
4-
(0 <= i && i < 10) ==> arr[i] == 0
5-
})
2+
int f1(int *arr)
3+
__CPROVER_assigns(*arr)
4+
__CPROVER_ensures(__CPROVER_forall {
5+
int i;
6+
(0 <= i && i < 10) ==> arr[i] == 0
7+
})
68
// clang-format on
79
{
810
for(int i = 0; i < 10; i++)

regression/contracts/quantifiers-nested-01/main.c

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
// clang-format off
2-
int f1(int *arr) __CPROVER_ensures(__CPROVER_forall {
3-
int i;
4-
__CPROVER_forall
5-
{
6-
int j;
7-
(0 <= i && i < 10 && i <= j && j < 10) ==> arr[i] <= arr[j]
8-
}
9-
})
2+
int f1(int *arr)
3+
__CPROVER_assigns(*arr)
4+
__CPROVER_ensures(__CPROVER_forall {
5+
int i;
6+
__CPROVER_forall
7+
{
8+
int j;
9+
(0 <= i && i < 10 && i <= j && j < 10) ==> arr[i] <= arr[j]
10+
}
11+
})
1012
// clang-format on
1113
{
1214
for(int i = 0; i < 10; i++)

regression/contracts/quantifiers-nested-03/main.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
int f1(int *arr)
1+
int f1(int *arr) __CPROVER_assigns(*arr)
22
__CPROVER_ensures(__CPROVER_return_value == 0 && __CPROVER_exists {
33
int i;
44
(0 <= i && i < 10) && arr[i] == i

src/goto-instrument/code_contracts.cpp

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -513,20 +513,8 @@ void code_contractst::instrument_call_statement(
513513

514514
exprt called_assigns =
515515
to_code_with_contract_type(called_symbol.type).assigns();
516-
if(called_assigns.is_nil()) // Called function has no assigns clause
517-
{
518-
// Create a false assertion, so the analysis
519-
// will fail if this function is called.
520-
goto_programt failing_assertion;
521-
failing_assertion.add(goto_programt::make_assertion(
522-
false_exprt(), instruction_iterator->source_location));
523-
program.insert_before_swap(instruction_iterator, failing_assertion);
524-
++instruction_iterator;
525-
526-
return;
527-
}
528-
else // Called function has assigns clause
529-
{
516+
if(!called_assigns.is_nil()) // Called function has assigns clause
517+
{
530518
replace_symbolt replace;
531519
// Replace formal parameters
532520
code_function_callt::argumentst::const_iterator a_it =
@@ -634,9 +622,6 @@ bool code_contractst::add_pointer_checks(const std::string &function_name)
634622
const auto &type = to_code_with_contract_type(function_symbol.type);
635623

636624
exprt assigns_expr = type.assigns();
637-
// Return if there are no reference checks to perform.
638-
if(assigns_expr.is_nil())
639-
return false;
640625

641626
assigns_clauset assigns(assigns_expr, *this, function_id, log);
642627

0 commit comments

Comments
 (0)