Skip to content

Commit 202359e

Browse files
committed
Add support for nested quantifiers in function contracts
This adds support for nested quantifiers in funtion contracts. We recusrively handle quantifiers that are nested within other quantifiers or within and/or/implies statements.
1 parent d98b56b commit 202359e

File tree

10 files changed

+152
-18
lines changed

10 files changed

+152
-18
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// 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+
})
10+
// clang-format on
11+
{
12+
for(int i = 0; i < 10; i++)
13+
{
14+
arr[i] = i;
15+
}
16+
17+
return 0;
18+
}
19+
20+
int main()
21+
{
22+
int arr[10];
23+
f1(arr);
24+
}
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=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
--
9+
Verification:
10+
This test asserts the postconditions of f1.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// clang-format off
2+
int f1(int *arr) __CPROVER_requires(__CPROVER_forall {
3+
int i;
4+
0 <= i && i < 9 ==> __CPROVER_forall
5+
{
6+
int j;
7+
(i <= j && j < 10) ==> arr[i] <= arr[j]
8+
}
9+
}) __CPROVER_ensures(__CPROVER_return_value == 0)
10+
// clang-format on
11+
{
12+
return 0;
13+
}
14+
15+
int main()
16+
{
17+
int arr[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
18+
f1(arr);
19+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
main.c
3+
--replace-all-calls-with-contracts
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
--
9+
Verification:
10+
This test asserts the preconditions of f1.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
int f1(int *arr)
2+
__CPROVER_ensures(__CPROVER_return_value == 0 && __CPROVER_exists {
3+
int i;
4+
(0 <= i && i < 10) && arr[i] == i
5+
})
6+
{
7+
for(int i = 0; i < 10; i++)
8+
{
9+
arr[i] = i;
10+
}
11+
12+
return 0;
13+
}
14+
15+
int main()
16+
{
17+
int arr[10];
18+
f1(arr);
19+
}
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=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
--
9+
Verification:
10+
This test asserts the postconditions of f1.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// clang-format off
2+
int f1(int *arr) __CPROVER_requires(
3+
__CPROVER_forall {
4+
int i;
5+
(0 <= i && i < 10) ==> arr[i] == 0
6+
} ||
7+
arr[9] == -1 ||
8+
__CPROVER_exists {
9+
int i;
10+
(0 <= i && i < 10) && arr[i] == i
11+
}) __CPROVER_ensures(__CPROVER_return_value == 0)
12+
// clang-format on
13+
{
14+
return 0;
15+
}
16+
17+
int main()
18+
{
19+
int arr[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
20+
f1(arr);
21+
}
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=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
--
9+
Verification:
10+
This test asserts the postconditions of f1.

src/goto-instrument/code_contracts.cpp

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -168,23 +168,29 @@ void code_contractst::add_quantified_variable(
168168
replace_symbolt &replace,
169169
irep_idt mode)
170170
{
171-
// If the expression is a quantified expression, this function adds
172-
// the quantified variable to the symbol table and to the expression map
173-
174-
// TODO Currently only works if the contract contains only a single
175-
// quantified formula
176-
// i.e. (1) the top-level element is a quantifier formula
177-
// and (2) there are no inner quantifier formulae
178-
// This TODO is handled in PR #5968
179-
180-
if(expression.id() == ID_exists || expression.id() == ID_forall)
181-
{
182-
// get quantified symbol
183-
exprt tuple = expression.operands().front();
184-
exprt quantified_variable = tuple.operands().front();
171+
// This function recursively searches the expression to find nested or
172+
// non-nested quantified expressions. When a quantified expression is found,
173+
// the quantified variable is added to the symbol table and to the expression map.
174+
if(
175+
expression.id() == ID_and || expression.id() == ID_or ||
176+
expression.id() == ID_implies)
177+
{
178+
// For binary connectives, recursively check for
179+
// nested quantified formulae in the left and right terms
180+
exprt left = expression.operands().at(0);
181+
add_quantified_variable(left, replace, mode);
182+
exprt right = expression.operands().at(1);
183+
add_quantified_variable(right, replace, mode);
184+
}
185+
else if(expression.id() == ID_exists || expression.id() == ID_forall)
186+
{
187+
// When a quantified expression is found,
188+
// 1. get quantified symbol
189+
exprt tuple = expression.operands().at(0);
190+
exprt quantified_variable = tuple.operands().at(0);
185191
symbol_exprt quantified_symbol = to_symbol_expr(quantified_variable);
186192

187-
// create fresh symbol
193+
// 2. create fresh symbol
188194
symbolt new_symbol = get_fresh_aux_symbol(
189195
quantified_symbol.type(),
190196
id2string(quantified_symbol.get_identifier()),
@@ -193,10 +199,14 @@ void code_contractst::add_quantified_variable(
193199
mode,
194200
symbol_table);
195201

196-
// add created fresh symbol to expression map
202+
// 3. add created fresh symbol to expression map
197203
symbol_exprt q(
198204
quantified_symbol.get_identifier(), quantified_symbol.type());
199205
replace.insert(q, new_symbol.symbol_expr());
206+
207+
// 4. recursively check for nested quantified formulae
208+
exprt quantified_expression = expression.operands().at(1);
209+
add_quantified_variable(quantified_expression, replace, mode);
200210
}
201211
}
202212

src/goto-instrument/code_contracts.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,8 +167,9 @@ class code_contractst
167167
void
168168
add_contract_check(const irep_idt &, const irep_idt &, goto_programt &dest);
169169

170-
/// If the expression is a quantified expression, this function adds
171-
/// the quantified variable to the symbol table and to the expression map
170+
// This function recursively searches the expression to find nested or
171+
// non-nested quantified expressions. When a quantified expression is found,
172+
// the quantified variable is added to the symbol table and to the expression map.
172173
void add_quantified_variable(
173174
exprt expression,
174175
replace_symbolt &replace,

0 commit comments

Comments
 (0)