Skip to content

Commit f6e22e9

Browse files
author
Remi Delmas
committed
contract enforcement alpha
1 parent 6c9eb84 commit f6e22e9

File tree

8 files changed

+502
-198
lines changed

8 files changed

+502
-198
lines changed

src/goto-instrument/contracts/dfcc.cpp

+10-71
Original file line numberDiff line numberDiff line change
@@ -247,14 +247,14 @@ void dfcct::transform_goto_model(
247247
// generate assignable_t functions from contracts
248248
for(const auto &function_id : spec_assigns_from_contract_functions)
249249
{
250-
dsl_contract_handler.dfcc_spec_assigns_function_from_contract(
250+
dsl_contract_handler.create_spec_assigns_function_from_contract(
251251
function_id, spec_assigns_functions);
252252
}
253253

254254
// inline all assignable_t functions
255255
for(const auto &function_id : spec_assigns_functions)
256256
{
257-
inline_and_check_loop_freeness(function_id);
257+
utils.inline_and_check_loop_freeness(function_id);
258258
}
259259

260260
// instrument all assignable_t functions
@@ -266,14 +266,14 @@ void dfcct::transform_goto_model(
266266
// generate frees_t functions from contracts
267267
for(const auto &function_id : spec_frees_from_contract_functions)
268268
{
269-
dsl_contract_handler.dfcc_spec_frees_function_from_contract(
269+
dsl_contract_handler.create_spec_frees_function_from_contract(
270270
function_id, spec_frees_functions);
271271
}
272272

273273
// inline all frees_t functions
274274
for(const auto &function_id : spec_frees_functions)
275275
{
276-
inline_and_check_loop_freeness(function_id);
276+
utils.inline_and_check_loop_freeness(function_id);
277277
}
278278

279279
// instrument all frees_t functions
@@ -327,7 +327,8 @@ void dfcct::transform_harness_function(const irep_idt &function_id)
327327
{
328328
/*
329329
Transforming the harness function just consists in passing a NULL value
330-
for the __dfcc_set parameter to each function call or function pointer call.
330+
for the assignable_set parameter to each function call or
331+
function pointer call.
331332
This will result in no DFCC set updates or checks being performed in
332333
functions called directly from the harness.
333334
*/
@@ -399,7 +400,7 @@ const symbolt &dfcct::add_dfcc_param(const irep_idt &function_id)
399400
const auto &sym = utils.create_symbol(
400401
library.dfcc_type[dfcc_typet::SET_PTR],
401402
id2string(function_id),
402-
"__dfcc_set",
403+
"__to_check",
403404
function_symbol.location,
404405
function_symbol.mode,
405406
function_symbol.module,
@@ -413,68 +414,6 @@ const symbolt &dfcct::add_dfcc_param(const irep_idt &function_id)
413414
return sym;
414415
}
415416

416-
const symbolt &dfcct::add_dfcc_local(
417-
const irep_idt &function_id,
418-
const int contract_assigns_size_hint,
419-
const bool contract_frees_append,
420-
goto_programt &decl_init,
421-
goto_programt &dead)
422-
{
423-
const auto &function_symbol = utils.get_function_symbol(function_id);
424-
425-
const auto &sym = utils.create_symbol(
426-
library.dfcc_type[dfcc_typet::SET],
427-
id2string(function_id),
428-
"__dfcc_set_local",
429-
function_symbol.location,
430-
function_symbol.mode,
431-
function_symbol.module,
432-
false);
433-
434-
const auto sym_expr = sym.symbol_expr();
435-
decl_init.add(goto_programt::make_decl(sym_expr));
436-
437-
// initialise
438-
auto function_sym_expr =
439-
library.dfcc_fun_symbol.at(dfcc_funt::SET_CREATE).symbol_expr();
440-
code_function_callt code_function_call(function_sym_expr);
441-
auto &arguments = code_function_call.arguments();
442-
arguments.emplace_back(address_of_exprt(sym_expr));
443-
arguments.emplace_back(from_integer(contract_assigns_size_hint, size_type()));
444-
arguments.emplace_back(
445-
(contract_frees_append ? (exprt)true_exprt() : (exprt)false_exprt()));
446-
447-
// kill
448-
dead.add(goto_programt::make_dead(sym_expr));
449-
return sym;
450-
}
451-
452-
void dfcct::inline_and_check_loop_freeness(const irep_idt &function_id)
453-
{
454-
auto &goto_function = goto_model.goto_functions.function_map.at(function_id);
455-
456-
PRECONDITION_WITH_DIAGNOSTICS(
457-
goto_function.body_available(),
458-
"dfcc: function " + id2string(function_id) + " must have a body");
459-
460-
inlining_decoratort decorated(log.get_message_handler());
461-
namespacet ns{goto_model.symbol_table};
462-
goto_function_inline(
463-
goto_model.goto_functions, function_id, ns, log.get_message_handler());
464-
465-
PRECONDITION_WITH_DIAGNOSTICS(
466-
decorated.get_recursive_function_warnings_count() == 0,
467-
"dfcc: function " + id2string(function_id) +
468-
" must not contain recursive function calls");
469-
470-
PRECONDITION_WITH_DIAGNOSTICS(
471-
is_loop_free(goto_function.body, ns, log),
472-
"dfcc: function " + id2string(function_id) + " must not contain loops");
473-
474-
// restore internal invariants
475-
goto_model.goto_functions.update();
476-
}
477-
478417
void dfcct::to_dfcc_spec_assigns_function(const irep_idt &function_id)
479418
{
480419
log.debug() << "dfcc: to_dfcc_spec_assigns_function(" << function_id << ")"
@@ -488,7 +427,7 @@ void dfcct::to_dfcc_spec_assigns_function(const irep_idt &function_id)
488427

489428
// add __dfcc_set parameter
490429
auto &set_symbol = utils.add_parameter(
491-
function_id, "__dfcc_set", library.dfcc_type[dfcc_typet::SET_PTR]);
430+
function_id, "__to_populate", library.dfcc_type[dfcc_typet::SET_PTR]);
492431

493432
// rewrite calls
494433
Forall_goto_program_instructions(ins_it, goto_function.body)
@@ -525,8 +464,8 @@ void dfcct::to_dfcc_spec_assigns_function(const irep_idt &function_id)
525464
{
526465
INVARIANT(
527466
false,
528-
"to_dfcc_spec_assigns_function: function calls must be inlined "
529-
"before calling this function");
467+
"dfcct::to_dfcc_spec_assigns_function: function calls must be "
468+
"inlined before calling this function");
530469
}
531470
}
532471
}

src/goto-instrument/contracts/dfcc.h

+10-19
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,16 @@ class dfcct
117117
/// Aborts on recursion warnings during inlining.
118118
void inline_and_check_loop_freeness(const irep_idt &function_id);
119119

120-
/// Transforms a function that returns __CPROVER_assignable_t into a function
121-
/// that accepts an extra __CPROVER_assignable_car_set_t parameter
120+
/// Transforms a function `__CPROVER_assignable_t foo(params)` into
121+
/// ```
122+
/// __CPROVER_assignable_t foo(
123+
/// params,
124+
/// __CPROVER_assignable_set_t populate,
125+
/// __CPROVER_assignable_set_t side_effect_check
126+
/// )
127+
/// ```
128+
/// - `populate` is the set to populate.
129+
/// - `side_effect` is the set to use for checking side effects.
122130
/// The function must have been previously inlined and be loop-free.
123131
void to_dfcc_spec_assigns_function(const irep_idt &function_id);
124132

@@ -140,23 +148,6 @@ class dfcct
140148
/// Adds the __dfcc_set parameter to the given function.
141149
const symbolt &add_dfcc_param(const irep_idt &function_id);
142150

143-
/// \brief Generates a local symbol and initialisation of a assignable set
144-
/// in the given function.
145-
/// \param function_id name of the function to generate code for
146-
/// \param contract_assigns_size_hint size hint to initialise contract_assigns
147-
/// \param contract_frees_append if true, activates append mode on the
148-
/// which is required when building an assignable set for contract replacement
149-
/// and enable SET_CHECK_ASSIGNS_CLAUSE_INCLUSION,
150-
/// SET_CHECK_FREES_CLAUSE_INCLUSION, SET_DEALLOCATE_FREEABLE
151-
/// \param decl_init program where declaration and initialisation are added
152-
/// \param dead program where dead instruction is added
153-
const symbolt &add_dfcc_local(
154-
const irep_idt &function_id,
155-
const int contract_assigns_size_hint,
156-
const bool contract_frees_append,
157-
goto_programt &decl_init,
158-
goto_programt &dead);
159-
160151
/// Wraps the given function_id
161152
/// in a wrapper that checks the given contract_id against the function.
162153
///

src/goto-instrument/contracts/dfcc_library.cpp

+52
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Author: Remi Delmas, [email protected]
1313
#include <util/message.h>
1414

1515
#include <goto-programs/goto_convert_functions.h>
16+
#include <goto-programs/goto_function.h>
1617
#include <goto-programs/goto_model.h>
1718

1819
#include <ansi-c/cprover_library.h>
@@ -89,6 +90,18 @@ const std::map<irep_idt, dfcc_funt> dfcc_libraryt::dfcc_hook = {
8990
{CPROVER_PREFIX "object_upto", dfcc_funt::SET_INSERT_OBJECT_UPTO},
9091
{CPROVER_PREFIX "freeable", dfcc_funt::SET_ADD_FREEABLE}};
9192

93+
const std::set<irep_idt> dfcc_libraryt::assignable_builtin_names = {
94+
CPROVER_PREFIX "assignable",
95+
CPROVER_PREFIX "assignable_set_insert_assignable",
96+
CPROVER_PREFIX "whole_object",
97+
CPROVER_PREFIX "assignable_set_insert_whole_object",
98+
CPROVER_PREFIX "object_from",
99+
CPROVER_PREFIX "assignable_set_insert_object_from",
100+
CPROVER_PREFIX "object_upto",
101+
CPROVER_PREFIX "assignable_set_insert_object_upto",
102+
CPROVER_PREFIX "freeable",
103+
CPROVER_PREFIX "assignable_set_add_freeable"};
104+
92105
const std::map<dfcc_funt, std::pair<bool, bool>>
93106
dfcc_libraryt::inline_and_unwind = {
94107
{dfcc_funt::CAR_CREATE, {false, false}},
@@ -195,3 +208,42 @@ void dfcc_libraryt::load()
195208
dfcc_type[pair.first] = ns.lookup(pair.second).type;
196209
}
197210
}
211+
212+
const int
213+
dfcc_libraryt::count_calls_to_buitins(const goto_functiont &goto_function)
214+
{
215+
int nof_calls = 0;
216+
forall_goto_program_instructions(ins_it, goto_function.body)
217+
{
218+
if(ins_it->is_function_call())
219+
{
220+
if(ins_it->call_function().id() != ID_symbol)
221+
{
222+
log.error().source_location = ins_it->source_location();
223+
log.error() << "dfcc: function pointer calls not supported"
224+
<< messaget::eom;
225+
throw 0;
226+
}
227+
228+
const irep_idt &callee_id =
229+
to_symbol_expr(ins_it->call_function()).get_identifier();
230+
231+
// only process built-in functions that return assignable_t,
232+
// error out on any other function call
233+
// find the corresponding instrumentation hook
234+
auto found = assignable_builtin_names.find(callee_id);
235+
if(found != assignable_builtin_names.end())
236+
{
237+
++nof_calls;
238+
}
239+
else
240+
{
241+
INVARIANT(
242+
false,
243+
"dfcc_libraryt::count_calls_to_buitins: all function calls must be "
244+
"inlined before calling this function");
245+
}
246+
}
247+
}
248+
return nof_calls;
249+
}

src/goto-instrument/contracts/dfcc_library.h

+10
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ enum class dfcc_funt
6262
};
6363

6464
class goto_modelt;
65+
class goto_functiont;
6566
class messaget;
6667
class message_handlert;
6768
class symbolt;
@@ -97,6 +98,9 @@ class dfcc_libraryt
9798
/// built-in function name to enum
9899
static const std::map<irep_idt, dfcc_funt> dfcc_hook;
99100

101+
/// built-in function names (front-end and instrumentation hooks)
102+
static const std::set<irep_idt> assignable_builtin_names;
103+
100104
/// true iff the library function must be inlined and unwound
101105
static const std::map<dfcc_funt, std::pair<bool, bool>> inline_and_unwind;
102106

@@ -111,6 +115,12 @@ class dfcc_libraryt
111115

112116
/// Adds all the `cprover_dfcc.c` library types and functions to the model
113117
void load();
118+
119+
/// Given a goto function representing an assigns clause, counts
120+
/// and returns the number of function calls to built-in
121+
/// __CPROVER_assignable_t functions it contains.
122+
/// Any call other than to a built-in makes the function fail
123+
const int count_calls_to_buitins(const goto_functiont &goto_function);
114124
};
115125

116126
#endif

0 commit comments

Comments
 (0)