Skip to content

Commit 3183180

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

File tree

7 files changed

+475
-138
lines changed

7 files changed

+475
-138
lines changed

src/goto-instrument/contracts/dfcc.cpp

+4-30
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
@@ -449,32 +449,6 @@ const symbolt &dfcct::add_dfcc_local(
449449
return sym;
450450
}
451451

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-
478452
void dfcct::to_dfcc_spec_assigns_function(const irep_idt &function_id)
479453
{
480454
log.debug() << "dfcc: to_dfcc_spec_assigns_function(" << function_id << ")"

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

src/goto-instrument/contracts/dfcc_utils.cpp

+56-23
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,14 @@ Author: Remi Delmas, [email protected]
2020
#include <util/std_types.h>
2121

2222
#include <goto-programs/goto_convert_functions.h>
23+
#include <goto-programs/goto_inline.h>
2324
#include <goto-programs/goto_model.h>
2425

2526
#include <ansi-c/c_expr.h>
2627
#include <linking/static_lifetime_init.h>
2728

29+
#include "utils.h"
30+
2831
dfcc_utilst::dfcc_utilst(goto_modelt &goto_model, messaget &log)
2932
: goto_model(goto_model), log(log), message_handler(log.get_message_handler())
3033
{
@@ -48,7 +51,7 @@ const symbolt &dfcc_utilst::create_symbol(
4851
const irep_idt &module,
4952
bool is_parameter)
5053
{
51-
log.debug() << "dfcc_utilst: create_symbol(" << prefix << "::" << base_name
54+
log.debug() << "dfcc_utilst::create_symbol(" << prefix << "::" << base_name
5255
<< ")" << messaget::eom;
5356

5457
symbolt &symbol = get_fresh_aux_symbol(
@@ -70,7 +73,7 @@ const symbolt &dfcc_utilst::create_static_symbol(
7073
const irep_idt &module,
7174
const exprt &initial_value)
7275
{
73-
log.debug() << "dfcc_utilst: create_static_symbol(" << prefix
76+
log.debug() << "dfcc_utilst::create_static_symbol(" << prefix
7477
<< "::" << base_name << ")" << messaget::eom;
7578

7679
symbolt &symbol = get_fresh_aux_symbol(
@@ -115,7 +118,7 @@ const symbolt &dfcc_utilst::add_parameter(
115118
const std::string &base_name,
116119
const typet &type)
117120
{
118-
log.debug() << "dfcc_utilst: add_parameter(" << function_id << ", "
121+
log.debug() << "dfcc_utilst::add_parameter(" << function_id << ", "
119122
<< base_name << ")" << messaget::eom;
120123

121124
symbolt &function_symbol = get_function_symbol(function_id);
@@ -144,14 +147,14 @@ const symbolt &dfcc_utilst::clone_and_rename_function(
144147
std::function<const typet(const typet &)> &trans_ret_type,
145148
std::function<const source_locationt(const source_locationt &)> &trans_loc)
146149
{
147-
log.debug() << "dfcc_utilst: clone_and_rename_function(" << function_id << ")"
150+
log.debug() << "dfcc_utilst::clone_and_rename_function(" << function_id << ")"
148151
<< messaget::eom;
149152
const symbolt &old_function_symbol = get_function_symbol(function_id);
150153
code_typet old_code_type = to_code_type(old_function_symbol.type);
151154

152155
irep_idt new_function_id = trans_fun(function_id);
153156

154-
log.debug() << "dfcc_utilst: clone_and_rename_function: function "
157+
log.debug() << "dfcc_utilst::clone_and_rename_function: function "
155158
<< function_id << "->" << new_function_id << messaget::eom;
156159

157160
code_typet::parameterst new_params;
@@ -180,7 +183,7 @@ const symbolt &dfcc_utilst::clone_and_rename_function(
180183

181184
if(!goto_model.symbol_table.add(new_function_symbol))
182185
{
183-
log.error() << "dfcc_utilst: clone_and_rename_function: renamed function "
186+
log.error() << "dfcc_utilst::clone_and_rename_function: renamed function "
184187
<< function_id << " -> " << new_function_id << " already exists"
185188
<< messaget::eom;
186189
exit(0);
@@ -225,7 +228,7 @@ void dfcc_utilst::clone_parameters(
225228
new_params.push_back(new_param);
226229

227230
// build symbol
228-
log.debug() << "dfcc_utilst: clone_parameters: param " << old_base_name
231+
log.debug() << "dfcc_utilst::clone_parameters: param " << old_base_name
229232
<< "->" << new_param_id << messaget::eom;
230233
parameter_symbolt new_param_symbol;
231234
new_param_symbol.base_name = new_base_name;
@@ -237,7 +240,7 @@ void dfcc_utilst::clone_parameters(
237240
new_param_symbol.location = location;
238241
if(!goto_model.symbol_table.add(new_param_symbol))
239242
{
240-
log.error() << "dfcc_utilst: clone_parameters: renamed parameter "
243+
log.error() << "dfcc_utilst::clone_parameters: renamed parameter "
241244
<< old_param.get_identifier() << " -> "
242245
<< new_param.get_identifier() << " already exists"
243246
<< messaget::eom;
@@ -248,12 +251,11 @@ void dfcc_utilst::clone_parameters(
248251

249252
const symbolt &dfcc_utilst::clone_and_rename_function(
250253
const irep_idt &function_id,
251-
const std::string &suffix,
254+
const irep_idt &new_function_id,
252255
optionalt<typet> new_return_type = {})
253256
{
254257
std::function<const irep_idt(const irep_idt &)> trans_fun =
255-
[&](const irep_idt &old_name)
256-
{ return id2string(old_name) + "::" + suffix; };
258+
[&](const irep_idt &old_name) { return new_function_id; };
257259

258260
std::function<const irep_idt(const irep_idt &)> trans_param =
259261
[&](const irep_idt &old_name) { return old_name; };
@@ -279,7 +281,7 @@ void dfcc_utilst::wrap_function(
279281
auto old_function = goto_functions.function_map.find(function_id);
280282
INVARIANT(
281283
old_function != goto_functions.function_map.end(),
282-
"dfcc_utilst: function to wrap " + id2string(function_id) +
284+
"dfcc_utilst::wrap_function: function to wrap " + id2string(function_id) +
283285
" must exist in the program");
284286

285287
// Register the wrapped function under the new name
@@ -290,7 +292,8 @@ void dfcc_utilst::wrap_function(
290292
INVARIANT(
291293
goto_functions.function_map.find(wrapped_function_id) !=
292294
goto_functions.function_map.end(),
293-
"dfcc_utilst: wrapped function " + id2string(wrapped_function_id) +
295+
"dfcc_utilst::wrap_function: wrapped function " +
296+
id2string(wrapped_function_id) +
294297
" shall exist in function_map at this point");
295298

296299
// Remove previous entry
@@ -300,7 +303,8 @@ void dfcc_utilst::wrap_function(
300303
INVARIANT(
301304
goto_functions.function_map.find(function_id) ==
302305
goto_functions.function_map.end(),
303-
"dfcc_utilst: the original function " + id2string(function_id) +
306+
"dfcc_utilst::wrap_function: the original function " +
307+
id2string(function_id) +
304308
" shall not exist in function_map anymore at this point");
305309

306310
// Add new symbol for the wrapped function in the symbol table
@@ -316,8 +320,8 @@ void dfcc_utilst::wrap_function(
316320
const auto wrapped_found = symbol_table.insert(std::move(wrapped_sym));
317321
INVARIANT(
318322
wrapped_found.second,
319-
"dfcc_utilst: wrapped function symbol " + id2string(wrapped_function_id) +
320-
" already exists in the symbol table");
323+
"dfcc_utilst::wrap_function: wrapped function symbol " +
324+
id2string(wrapped_function_id) + " already exists in the symbol table");
321325

322326
// Re-insert a symbol for `function_id` which is now the wrapper function
323327
symbolt wrapper_sym;
@@ -347,17 +351,17 @@ void dfcc_utilst::wrap_function(
347351
// Remove original symbol from the symbol_table
348352
if(!goto_model.symbol_table.remove(function_id))
349353
{
350-
log.error() << "dfcc_utilst: could not remove " << function_id
351-
<< " from the symbol table" << messaget::eom;
354+
log.error() << "dfcc_utilst::wrap_function: could not remove "
355+
<< function_id << " from the symbol table" << messaget::eom;
352356
exit(0);
353357
}
354358

355359
// Insert update symbol in the symbol_table
356360
const auto wrapper_sym_found = symbol_table.insert(std::move(wrapper_sym));
357361
INVARIANT(
358362
wrapper_sym_found.second,
359-
"dfcc_utilst: could not insert symbol " + id2string(function_id) +
360-
" in the symbol table");
363+
"dfcc_utilst::wrap_function: could not insert symbol " +
364+
id2string(function_id) + " in the symbol table");
361365

362366
// Insert wrapper function in the function_map
363367
goto_functiont &wrapper_fun = goto_functions.function_map[function_id];
@@ -372,14 +376,15 @@ const exprt dfcc_utilst::make_null_check_expr(const exprt &ptr)
372376

373377
exprt dfcc_utilst::make_sizeof_expr(const exprt &expr)
374378
{
375-
log.debug() << "dfcc_utilst : make_sizeof_expr(" << format(expr) << ")"
379+
log.debug() << "dfcc_utilst::make_sizeof_expr(" << format(expr) << ")"
376380
<< messaget::eom;
377381
const auto &size =
378382
size_of_expr(expr.type(), namespacet(goto_model.symbol_table));
379383

380384
PRECONDITION_WITH_DIAGNOSTICS(
381385
size.has_value(),
382-
"dfcc_utilst: no definite size for lvalue target:\n" + expr.pretty());
386+
"dfcc_utilst::make_sizeof_expr: no definite size for lvalue target:\n" +
387+
expr.pretty());
383388

384389
return typecast_exprt::conditional_cast(size.value(), size_type());
385390
}
@@ -389,4 +394,32 @@ exprt dfcc_utilst::make_map_start_address(const exprt &expr)
389394
return typecast_exprt::conditional_cast(
390395
address_of_exprt(index_exprt(expr, from_integer(0, c_index_type()))),
391396
pointer_type(bool_typet()));
392-
}
397+
}
398+
399+
void dfcc_utilst::inline_and_check_loop_freeness(const irep_idt &function_id)
400+
{
401+
auto &goto_function = goto_model.goto_functions.function_map.at(function_id);
402+
403+
PRECONDITION_WITH_DIAGNOSTICS(
404+
goto_function.body_available(),
405+
"dfcc_utilst::inline_and_check_loop_freeness: function " +
406+
id2string(function_id) + " must have a body");
407+
408+
inlining_decoratort decorated(log.get_message_handler());
409+
namespacet ns{goto_model.symbol_table};
410+
goto_function_inline(
411+
goto_model.goto_functions, function_id, ns, log.get_message_handler());
412+
413+
PRECONDITION_WITH_DIAGNOSTICS(
414+
decorated.get_recursive_function_warnings_count() == 0,
415+
"dfcc_utilst::inline_and_check_loop_freeness: function " +
416+
id2string(function_id) + " must not contain recursive function calls");
417+
418+
PRECONDITION_WITH_DIAGNOSTICS(
419+
is_loop_free(goto_function.body, ns, log),
420+
"dfcc_utilst::inline_and_check_loop_freeness: function " +
421+
id2string(function_id) + " must not contain loops");
422+
423+
// restore internal invariants
424+
goto_model.goto_functions.update();
425+
}

0 commit comments

Comments
 (0)