Skip to content

Commit 8fa5ac8

Browse files
committed
Update CLI for applyin loop contracts with dfcc
1 parent 2aec6a9 commit 8fa5ac8

File tree

7 files changed

+114
-32
lines changed

7 files changed

+114
-32
lines changed

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

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ void dfcc(
121121
const bool allow_recursive_calls,
122122
const std::set<irep_idt> &to_replace,
123123
const bool apply_loop_contracts,
124+
const bool unwind_transformed_loops,
124125
const std::set<std::string> &to_exclude_from_nondet_static,
125126
message_handlert &message_handler)
126127
{
@@ -137,6 +138,7 @@ void dfcc(
137138
allow_recursive_calls,
138139
to_replace_map,
139140
apply_loop_contracts,
141+
unwind_transformed_loops,
140142
to_exclude_from_nondet_static,
141143
message_handler);
142144
}
@@ -149,6 +151,7 @@ void dfcc(
149151
const bool allow_recursive_calls,
150152
const std::map<irep_idt, irep_idt> &to_replace,
151153
const bool apply_loop_contracts,
154+
const bool unwind_transformed_loops,
152155
const std::set<std::string> &to_exclude_from_nondet_static,
153156
message_handlert &message_handler)
154157
{
@@ -160,6 +163,7 @@ void dfcc(
160163
allow_recursive_calls,
161164
to_replace,
162165
apply_loop_contracts,
166+
unwind_transformed_loops,
163167
message_handler,
164168
to_exclude_from_nondet_static};
165169
}
@@ -172,6 +176,7 @@ dfcct::dfcct(
172176
const bool allow_recursive_calls,
173177
const std::map<irep_idt, irep_idt> &to_replace,
174178
const bool apply_loop_contracts,
179+
const bool unwind_transformed_loops,
175180
message_handlert &message_handler,
176181
const std::set<std::string> &to_exclude_from_nondet_static)
177182
: options(options),
@@ -213,9 +218,16 @@ dfcct::dfcct(
213218
library,
214219
spec_functions,
215220
contract_clauses_codegen),
216-
instrument(goto_model, message_handler, utils, loop_instrument, library),
221+
instrument(
222+
goto_model,
223+
message_handler,
224+
utils,
225+
loop_instrument,
226+
apply_loop_contracts,
227+
library),
217228
max_assigns_clause_size(0)
218229
{
230+
instrument.unwind_transformed_loops = unwind_transformed_loops;
219231
transform_goto_model();
220232
}
221233

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

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ class optionst;
6060
// clang-format off
6161
#define HELP_DFCC \
6262
"--dfcc <harness> activate dynamic frame condition checking for function\n"\
63-
" contracts using the given harness as entry point"
63+
" contracts using the given harness as entry point\n"
6464

6565
#define FLAG_ENFORCE_CONTRACT_REC "enforce-contract-rec"
6666
#define OPT_ENFORCE_CONTRACT_REC "(" FLAG_ENFORCE_CONTRACT_REC "):"
@@ -100,6 +100,8 @@ class invalid_function_contract_pair_exceptiont : public cprover_exception_baset
100100
/// \param allow_recursive_calls Allow the checked function to be recursive
101101
/// \param to_replace set of functions to replace with their contract
102102
/// \param apply_loop_contracts apply loop contract transformations iff true
103+
/// \param unwind_transformed_loops unwind transformed loops after applying loop
104+
/// contracts.
103105
/// \param to_exclude_from_nondet_static set of symbols to exclude when havocing
104106
/// static program symbols.
105107
/// \param message_handler used for debug/warning/error messages
@@ -111,6 +113,7 @@ void dfcc(
111113
const bool allow_recursive_calls,
112114
const std::set<irep_idt> &to_replace,
113115
const bool apply_loop_contracts,
116+
const bool unwind_transformed_loops,
114117
const std::set<std::string> &to_exclude_from_nondet_static,
115118
message_handlert &message_handler);
116119

@@ -129,7 +132,9 @@ void dfcc(
129132
/// \param to_check (function,contract) pair for contract checking
130133
/// \param allow_recursive_calls Allow the checked function to be recursive
131134
/// \param to_replace Functions-to-contract mapping for replacement
132-
/// \param apply_loop_contracts Spply loop contract transformations iff true
135+
/// \param apply_loop_contracts Apply loop contract transformations iff true
136+
/// \param unwind_transformed_loops unwind transformed loops after applying loop
137+
/// contracts.
133138
/// \param to_exclude_from_nondet_static Set of symbols to exclude when havocing
134139
/// static program symbols.
135140
/// \param message_handler used for debug/warning/error messages
@@ -141,6 +146,7 @@ void dfcc(
141146
const bool allow_recursive_calls,
142147
const std::map<irep_idt, irep_idt> &to_replace,
143148
const bool apply_loop_contracts,
149+
const bool unwind_transformed_loops,
144150
const std::set<std::string> &to_exclude_from_nondet_static,
145151
message_handlert &message_handler);
146152

@@ -159,6 +165,8 @@ class dfcct
159165
/// \param to_replace functions-to-contract mapping for replacement
160166
/// \param apply_loop_contracts apply loop contract transformations iff true
161167
/// havocing static program symbols.
168+
/// \param unwind_transformed_loops unwind transformed loops after applying
169+
/// loop contracts.
162170
/// \param message_handler used for debug/warning/error messages
163171
/// \param to_exclude_from_nondet_static set of symbols to exclude when
164172
dfcct(
@@ -169,6 +177,7 @@ class dfcct
169177
const bool allow_recursive_calls,
170178
const std::map<irep_idt, irep_idt> &to_replace,
171179
const bool apply_loop_contracts,
180+
const bool unwind_transformed_loops,
172181
message_handlert &message_handler,
173182
const std::set<std::string> &to_exclude_from_nondet_static);
174183

@@ -194,7 +203,7 @@ class dfcct
194203
/// (replacement mode)
195204
/// - instrument all remaining functions GOTO model
196205
/// - (this includes standard library functions).
197-
/// - specialise the instrumentation functions by unwiding loops they contain
206+
/// - specialise the instrumentation functions by unwinding loops they contain
198207
/// to the maximum size of any assigns clause involved in the model.
199208
void transform_goto_model();
200209

@@ -278,7 +287,7 @@ class dfcct
278287
/// for each instrumented function
279288
///
280289
/// A call to `nondet_static` will re-generate the initialize function with
281-
/// nondet values. The intrumentation statics will not get nondet initialised
290+
/// nondet values. The instrumentation statics will not get nondet initialised
282291
/// by virtue of being tagged with ID_C_no_nondet_initialization.
283292
///
284293
/// However, nondet_static expects instructions to be either function calls

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

Lines changed: 60 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ Author: Remi Delmas, [email protected]
2929
#include <goto-instrument/contracts/dynamic-frames/dfcc_loop_utils.h>
3030
#include <goto-instrument/contracts/utils.h>
3131
#include <goto-instrument/generate_function_bodies.h>
32+
#include <goto-instrument/unwind.h>
33+
#include <goto-instrument/unwindset.h>
3234
#include <langapi/language_util.h>
3335

3436
#include "dfcc_is_freeable.h"
@@ -47,12 +49,14 @@ dfcc_instrumentt::dfcc_instrumentt(
4749
message_handlert &message_handler,
4850
dfcc_utilst &utils,
4951
dfcc_loop_instrumentt &loop_instrument,
52+
const bool apply_loop_contracts,
5053
dfcc_libraryt &library)
5154
: goto_model(goto_model),
5255
message_handler(message_handler),
5356
log(message_handler),
5457
utils(utils),
5558
loop_instrument(loop_instrument),
59+
apply_loop_contracts(apply_loop_contracts),
5660
library(library),
5761
ns(goto_model.symbol_table)
5862
{
@@ -260,6 +264,31 @@ void dfcc_instrumentt::instrument_harness_function(
260264
dfcc_obeys_contractt obeys_contract(library, message_handler);
261265
obeys_contract.rewrite_calls(body, null_expr, function_pointer_contracts);
262266

267+
if(apply_loop_contracts)
268+
{
269+
// DECL write_set_to_check
270+
// ASSIGN write_set_to_check := NULL
271+
auto &goto_function =
272+
goto_model.goto_functions.function_map.at(function_id);
273+
const auto &write_set = utils.create_new_parameter_symbol(
274+
function_id,
275+
"write_set_to_check",
276+
library.dfcc_type[dfcc_typet::WRITE_SET_PTR]);
277+
auto first_instr = goto_function.body.instructions.begin();
278+
goto_function.body.insert_before(
279+
first_instr, goto_programt::make_decl(write_set.symbol_expr()));
280+
goto_function.body.insert_before(
281+
first_instr,
282+
goto_programt::make_assignment(write_set.symbol_expr(), null_expr));
283+
284+
goto_function.body.update();
285+
instrument_loops(
286+
function_id,
287+
goto_function,
288+
write_set.symbol_expr(),
289+
function_pointer_contracts);
290+
}
291+
263292
// rewrite calls
264293
Forall_goto_program_instructions(it, body)
265294
{
@@ -346,7 +375,6 @@ void dfcc_instrumentt::instrument_loops(
346375
const irep_idt &function_id,
347376
goto_functiont &goto_function,
348377
const exprt &write_set,
349-
cfg_infot &cfg_info,
350378
std::set<irep_idt> &function_pointer_contracts)
351379
{
352380
auto &function_body = goto_function.body;
@@ -385,10 +413,14 @@ void dfcc_instrumentt::instrument_loops(
385413
addr_of_loop_write_set;
386414
}
387415

416+
/// \brief Names of loops we are going to unwind.
417+
std::list<std::string> unwind_loop_names;
418+
388419
// Iterate over the (natural) loops in the function, in topo-sorted order,
389420
// and apply any loop contracts that we find.
390421
for(const auto &idx : loop_nesting_graph.topsort())
391422
{
423+
const auto loop_number = loop_nesting_graph[idx].latch_target->loop_number;
392424
const auto &loop_node = loop_nesting_graph[idx];
393425
if(
394426
loop_node.assigns_clause.is_nil() && loop_node.invariant.is_nil() &&
@@ -430,9 +462,9 @@ void dfcc_instrumentt::instrument_loops(
430462
}
431463
const auto write_set_ptr = expr_try_dynamic_cast<symbol_exprt>(write_set);
432464
const symbol_exprt &outer_write_set =
433-
(outer_idx == idx)
434-
? *write_set_ptr
435-
: loop_nesting_graph[outer_idx].write_set_symbol.symbol_expr();
465+
(outer_idx == idx) ? *write_set_ptr
466+
: loop_nesting_graph[outer_idx]
467+
.addr_of_loop_write_set_symbol.symbol_expr();
436468

437469
loop_instrument.instrument(
438470
function_id,
@@ -446,6 +478,25 @@ void dfcc_instrumentt::instrument_loops(
446478
outer_write_set,
447479
loop_nesting_graph.get_reachable(idx, false),
448480
utils.get_function_symbol(function_id).mode);
481+
482+
// We will unwind all transformed loops twice. Store the names of
483+
// to-unwind-loops here and perform the unwinding after transformation done.
484+
// As described in `check_apply_loop_contracts`, loops with loop contracts
485+
// will be transformed to a loop that execute exactly twice: one for base
486+
// case and one for step case. So we unwind them here to avoid users
487+
// incorrectly unwind them only once.
488+
std::string to_unwind =
489+
id2string(function_id) + "." + std::to_string(loop_number) + ":2";
490+
unwind_loop_names.push_back(to_unwind);
491+
}
492+
493+
// unwind all transformed loops twice.
494+
if(unwind_transformed_loops)
495+
{
496+
unwindsett unwindset{goto_model};
497+
unwindset.parse_unwindset(unwind_loop_names, log.get_message_handler());
498+
goto_unwindt goto_unwind;
499+
goto_unwind(goto_model, unwindset, goto_unwindt::unwind_strategyt::ASSUME);
449500
}
450501

451502
remove_skip(goto_model);
@@ -475,12 +526,11 @@ void dfcc_instrumentt::instrument_function_body(
475526
auto &body = goto_function.body;
476527

477528
// Instrument all loops in the function.
478-
instrument_loops(
479-
function_id,
480-
goto_function,
481-
write_set,
482-
cfg_info,
483-
function_pointer_contracts);
529+
if(apply_loop_contracts)
530+
{
531+
instrument_loops(
532+
function_id, goto_function, write_set, function_pointer_contracts);
533+
}
484534

485535
const auto &not_in_loop_filter =
486536
[&](const goto_programt::instructiont::targett &target) {

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ class dfcc_instrumentt
4545
message_handlert &message_handler,
4646
dfcc_utilst &utils,
4747
dfcc_loop_instrumentt &loop_instrument,
48+
const bool apply_loop_contracts,
4849
dfcc_libraryt &library);
4950

5051
/// True if id has `CPROVER_PREFIX` or `__VERIFIER` or `nondet` prefix,
@@ -149,19 +150,22 @@ class dfcc_instrumentt
149150
const irep_idt &function_id,
150151
goto_functiont &goto_function,
151152
const exprt &write_set,
152-
cfg_infot &cfg_info,
153153
std::set<irep_idt> &function_pointer_contracts);
154154

155155
/// Adds the names of instrumented functions to \p dest.
156156
/// The names are kept track of in the \ref function_cache field.
157157
void get_instrumented_functions(std::set<irep_idt> &dest) const;
158158

159+
/// \brief Unwind transformed loops after applying loop contracts or not.
160+
bool unwind_transformed_loops = true;
161+
159162
protected:
160163
goto_modelt &goto_model;
161164
message_handlert &message_handler;
162165
messaget log;
163166
dfcc_utilst &utils;
164167
dfcc_loop_instrumentt &loop_instrument;
168+
const bool apply_loop_contracts;
165169
dfcc_libraryt &library;
166170
namespacet ns;
167171

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

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,10 @@ void dfcc_loop_instrumentt::instrument(
115115
addr_of_loop_write_set, symbol_mode, assigns_instrs, nof_targets);
116116
write_set_populate_instrs.copy_from(assigns_instrs);
117117

118+
// replace bound variables by fresh instances
119+
if(has_subexpr(invariant, ID_exists) || has_subexpr(invariant, ID_forall))
120+
add_quantified_variable(symbol_table, invariant, symbol_mode);
121+
118122
// ---------- Start to add instrumented instructions ----------
119123
const auto &history_var_map = add_prehead_instructions(
120124
function_id,
@@ -244,7 +248,7 @@ std::map<exprt, exprt> dfcc_loop_instrumentt::add_prehead_instructions(
244248
goto_programt::targett loop_head,
245249
goto_programt::targett loop_latch,
246250
goto_programt &assigns_instrs,
247-
exprt invariant,
251+
exprt &invariant,
248252
const exprt::operandst &assigns,
249253
const symbol_exprt &loop_write_set,
250254
const symbol_exprt &addr_of_loop_write_set,
@@ -372,8 +376,8 @@ dfcc_loop_instrumentt::add_step_instructions(
372376
goto_programt::targett loop_head,
373377
goto_programt::targett loop_latch,
374378
goto_programt &havoc_instrs,
375-
exprt invariant,
376-
exprt decreases_clause,
379+
const exprt &invariant,
380+
const exprt &decreases_clause,
377381
const symbol_exprt &addr_of_loop_write_set,
378382
const symbol_exprt &outer_write_set,
379383
const symbol_exprt &initial_invariant_val,
@@ -696,7 +700,7 @@ void dfcc_loop_instrumentt::add_exit_instructions(
696700

697701
goto_programt pre_loop_exit_instrs;
698702
// Assertion to check that step case was checked if we entered the loop.
699-
source_locationt annotated_location = loop_head_location;
703+
source_locationt annotated_location = exit_target->source_location();
700704
annotated_location.set_comment(
701705
"Check that loop instrumentation was not truncated");
702706
pre_loop_exit_instrs.add(goto_programt::make_assertion(

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ class dfcc_loop_instrumentt
166166
goto_programt::targett loop_head,
167167
goto_programt::targett loop_latch,
168168
goto_programt &assigns_instrs,
169-
exprt invariant,
169+
exprt &invariant,
170170
const exprt::operandst &assigns,
171171
const symbol_exprt &loop_write_set,
172172
const symbol_exprt &addr_of_loop_write_set,
@@ -209,8 +209,8 @@ class dfcc_loop_instrumentt
209209
goto_programt::targett loop_head,
210210
goto_programt::targett loop_latch,
211211
goto_programt &havoc_instrs,
212-
exprt invariant,
213-
exprt decreases_clause,
212+
const exprt &invariant,
213+
const exprt &decreases_clause,
214214
const symbol_exprt &loop_write_set,
215215
const symbol_exprt &outer_write_set,
216216
const symbol_exprt &initial_invariant_val,

0 commit comments

Comments
 (0)