Skip to content

Commit b62358b

Browse files
authored
Merge pull request #7786 from remi-delmas-3000/contracts-fix-quantifier-vars
CONTRACTS: fix fresh symbols for quantified vars
2 parents da48fba + 8788466 commit b62358b

File tree

4 files changed

+63
-12
lines changed

4 files changed

+63
-12
lines changed
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#include <stdlib.h>
2+
void foo(char *dst, const char *src, size_t n)
3+
// clang-format off
4+
__CPROVER_requires(__CPROVER_is_fresh(src, n))
5+
__CPROVER_requires(__CPROVER_is_fresh(dst, n))
6+
__CPROVER_assigns(__CPROVER_object_from(dst))
7+
__CPROVER_ensures(__CPROVER_forall {
8+
size_t j;
9+
j < n ==> dst[j] == src[j]
10+
})
11+
// clang-format on
12+
{
13+
for(size_t i = 0; i < n; i++)
14+
// clang-format off
15+
__CPROVER_assigns(i, __CPROVER_object_from(dst))
16+
__CPROVER_loop_invariant(i <= n)
17+
__CPROVER_loop_invariant(
18+
__CPROVER_forall { size_t j; j < i ==> dst[j] == src[j] })
19+
// clang-format on
20+
{
21+
dst[i] = src[i];
22+
}
23+
}
24+
25+
int main()
26+
{
27+
char *dst;
28+
char *src;
29+
size_t n;
30+
foo(dst, src, n);
31+
return 0;
32+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
CORE dfcc-only smt-backend broken-cprover-smt-backend
2+
main.c
3+
--dfcc main --apply-loop-contracts --enforce-contract foo --malloc-may-fail --malloc-fail-null _ --z3 --slice-formula
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
^warning: ignoring
9+
--
10+
Tests support for quantifiers in loop contracts with the SMT backend.
11+
When quantified loop invariants are used, they are inserted three times
12+
in the transformed program (base case assertion, step case assumption,
13+
step case assertion), and each occurrence needs to be rewritten with fresh
14+
symbols for the quantified variables. The SMT solver would with an error
15+
whenever this renaming is not properly done.

src/goto-instrument/contracts/dynamic-frames/dfcc_instrument_loop.cpp

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -129,15 +129,10 @@ void dfcc_instrument_loopt::operator()(
129129
write_set_populate_instrs,
130130
nof_targets);
131131

132-
// Replace bound variables by fresh instances in quantified formulas.
133-
exprt invariant = loop.invariant;
134-
if(has_subexpr(invariant, ID_exists) || has_subexpr(invariant, ID_forall))
135-
add_quantified_variable(symbol_table, invariant, language_mode);
136-
137132
// ---------- Add instrumented instructions ----------
138133
goto_programt::targett loop_latch =
139134
loop.find_latch(goto_function.body).value();
140-
135+
exprt invariant(loop.invariant);
141136
const auto history_var_map = add_prehead_instructions(
142137
loop_id,
143138
goto_function,
@@ -240,7 +235,9 @@ dfcc_instrument_loopt::add_prehead_instructions(
240235
// GOTO HEAD;
241236
// ```
242237

243-
238+
// Replace bound variables by fresh instances in quantified formulas.
239+
if(has_subexpr(invariant, ID_exists) || has_subexpr(invariant, ID_forall))
240+
add_quantified_variable(symbol_table, invariant, language_mode);
244241
// initialize loop_entry history vars;
245242
auto replace_history_result = replace_history_loop_entry(
246243
symbol_table, invariant, loop_head_location, language_mode);
@@ -329,7 +326,7 @@ dfcc_instrument_loopt::add_step_instructions(
329326
goto_programt::targett loop_head,
330327
goto_programt::targett loop_latch,
331328
goto_programt &havoc_instrs,
332-
const exprt &invariant,
329+
exprt &invariant,
333330
const exprt::operandst &decreases_clauses,
334331
const symbol_exprt &addr_of_loop_write_set,
335332
const exprt &outer_write_set,
@@ -432,6 +429,9 @@ dfcc_instrument_loopt::add_step_instructions(
432429
dfcc_utilst::get_function_symbol(symbol_table, function_id).mode;
433430
{
434431
// Assume the loop invariant after havocing the state.
432+
// Replace bound variables by fresh instances in quantified formulas.
433+
if(has_subexpr(invariant, ID_exists) || has_subexpr(invariant, ID_forall))
434+
add_quantified_variable(symbol_table, invariant, language_mode);
435435
code_assumet assumption{invariant};
436436
assumption.add_source_location() = loop_head_location;
437437
converter.goto_convert(assumption, step_instrs, language_mode);
@@ -461,7 +461,7 @@ void dfcc_instrument_loopt::add_body_instructions(
461461
symbol_table_baset &symbol_table,
462462
goto_programt::targett loop_head,
463463
goto_programt::targett loop_latch,
464-
const exprt &invariant,
464+
exprt &invariant,
465465
const exprt::operandst &decreases_clauses,
466466
const symbol_exprt &entered_loop,
467467
const symbol_exprt &in_base_case,
@@ -512,6 +512,10 @@ void dfcc_instrument_loopt::add_body_instructions(
512512
"Check invariant after step for loop " +
513513
id2string(check_location.get_function()) + "." +
514514
std::to_string(cbmc_loop_id));
515+
// Assume the loop invariant after havocing the state.
516+
// Replace bound variables by fresh instances in quantified formulas.
517+
if(has_subexpr(invariant, ID_exists) || has_subexpr(invariant, ID_forall))
518+
add_quantified_variable(symbol_table, invariant, language_mode);
515519
code_assertt assertion{invariant};
516520
assertion.add_source_location() = check_location;
517521
converter.goto_convert(assertion, pre_loop_latch_instrs, language_mode);

src/goto-instrument/contracts/dynamic-frames/dfcc_instrument_loop.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ class dfcc_instrument_loopt
184184
/// \param[inout] loop_latch Latch node of the loop.
185185
/// \param[out] assigns_instrs `goto_programt` that contains instructions of
186186
/// populating assigns into the loop write set.
187-
/// \param[out] invariant Loop invariants.
187+
/// \param[in] invariant Loop invariants.
188188
/// \param[in] assigns Assigns targets of the loop.
189189
/// \param[in] loop_write_set Stack allocated loop write set variable.
190190
/// \param[in] addr_of_loop_write_set Loop write set pointer variable.
@@ -250,7 +250,7 @@ class dfcc_instrument_loopt
250250
goto_programt::targett loop_head,
251251
goto_programt::targett loop_latch,
252252
goto_programt &havoc_instrs,
253-
const exprt &invariant,
253+
exprt &invariant,
254254
const exprt::operandst &decreases_clauses,
255255
const symbol_exprt &loop_write_set,
256256
const exprt &outer_write_set,
@@ -296,7 +296,7 @@ class dfcc_instrument_loopt
296296
symbol_table_baset &symbol_table,
297297
goto_programt::targett loop_head,
298298
goto_programt::targett loop_latch,
299-
const exprt &invariant,
299+
exprt &invariant,
300300
const exprt::operandst &decreases_clauses,
301301
const symbol_exprt &entered_loop,
302302
const symbol_exprt &in_base_case,

0 commit comments

Comments
 (0)