CBMC
Loading...
Searching...
No Matches
dfcc_swap_and_wrap.cpp
Go to the documentation of this file.
1/*******************************************************************\
2
3Module: Dynamic frame condition checking
4
5Author: Remi Delmas, delmarsd@amazon.com
6
7\*******************************************************************/
8
10
12
14#include "dfcc_instrument.h"
15#include "dfcc_library.h"
16#include "dfcc_utils.h"
17
19 goto_modelt &goto_model,
20 message_handlert &message_handler,
21 dfcc_libraryt &library,
22 dfcc_instrumentt &instrument,
23 dfcc_spec_functionst &spec_functions,
24 dfcc_contract_handlert &contract_handler)
25 : goto_model(goto_model),
26 message_handler(message_handler),
27 log(message_handler),
28 library(library),
29 instrument(instrument),
30 spec_functions(spec_functions),
31 contract_handler(contract_handler),
32 ns(goto_model.symbol_table)
33{
34}
35
36// static map
37std::map<
39 std::pair<irep_idt, std::pair<dfcc_contract_modet, loop_contract_configt>>>
41
43 const dfcc_contract_modet contract_mode,
44 const loop_contract_configt &loop_contract_config,
45 const irep_idt &function_id,
46 const irep_idt &contract_id,
47 std::set<irep_idt> &function_pointer_contracts,
48 bool allow_recursive_calls)
49{
50 auto pair = cache.insert(
51 {function_id, {contract_id, {contract_mode, loop_contract_config}}});
52 auto inserted = pair.second;
53
54 if(!inserted)
55 {
56 irep_idt old_contract_id = pair.first->second.first;
57 dfcc_contract_modet old_contract_mode = pair.first->second.second.first;
59 pair.first->second.second.second;
60
61 // different swap already performed, abort (should be unreachable)
62 if(
63 old_contract_id != contract_id || old_contract_mode != contract_mode ||
64 old_loop_contract_config != loop_contract_config)
65 {
66 std::ostringstream err_msg;
67 err_msg << "DFCC: multiple attempts to swap and wrap function '"
68 << function_id << "':\n";
69 err_msg << "- with '" << old_contract_id << "' in "
71 << old_loop_contract_config.to_string() << "\n";
72 err_msg << "- with '" << contract_id << "' in "
73 << dfcc_contract_mode_to_string(contract_mode) << " "
74 << loop_contract_config.to_string() << "\n";
76 }
77 // same swap already performed
78 return;
79 }
80
81 // actually perform the translation
82 switch(contract_mode)
83 {
85 {
87 loop_contract_config,
88 function_id,
90 function_pointer_contracts,
91 allow_recursive_calls);
92 break;
93 }
95 {
96 replace_with_contract(function_id, contract_id, function_pointer_contracts);
97 break;
98 }
99 }
100}
101
102void dfcc_swap_and_wrapt::get_swapped_functions(std::set<irep_idt> &dest) const
103{
104 for(const auto &it : dfcc_swap_and_wrapt::cache)
105 {
106 dest.insert(it.first);
107 }
108}
109
135 const loop_contract_configt &loop_contract_config,
136 const irep_idt &function_id,
137 const irep_idt &contract_id,
138 std::set<irep_idt> &function_pointer_contracts,
139 bool allow_recursive_calls)
140{
141 // all code generation needs to run on functions with unmodified signatures
142 const irep_idt &wrapper_id = function_id;
143 const irep_idt wrapped_id =
144 id2string(wrapper_id) + "_wrapped_for_contract_checking";
146
147 // wrapper body
148 goto_programt body;
149
150 const auto &wrapper_symbol =
152
155 bool_typet(),
156 id2string(function_id),
157 "__contract_check_in_progress",
158 wrapper_symbol.location,
159 wrapper_symbol.mode,
160 wrapper_symbol.module,
161 false_exprt())
162 .symbol_expr();
163
166 bool_typet(),
167 id2string(function_id),
168 "__contract_checked_once",
169 wrapper_symbol.location,
170 wrapper_symbol.mode,
171 wrapper_symbol.module,
172 false_exprt())
173 .symbol_expr();
174
176 check_started, wrapper_symbol.location));
177
178 // At most a single top level call to the checked function in any execution
179
180 // Recursive calls within a contract check correspond to
181 // `check_started && !check_completed` and are allowed.
182
183 // Any other call occuring with `check_completed` true is forbidden.
184 source_locationt sl(wrapper_symbol.location);
185 sl.set_function(wrapper_symbol.name);
186 sl.set_property_class("single_top_level_call");
187 sl.set_comment(
188 "Only a single top-level call to function " + id2string(function_id) +
189 " when checking contract " + id2string(contract_id));
192 check_started, true_exprt(), wrapper_symbol.location));
193
196 function_id,
197 "__write_set_to_check",
199
206 body,
207 function_pointer_contracts);
208
210 check_completed, true_exprt(), wrapper_symbol.location));
212 check_started, false_exprt(), wrapper_symbol.location));
213
214 // unconditionally Jump to the end after the check
215 auto goto_end_function =
216 body.add(goto_programt::make_incomplete_goto(wrapper_symbol.location));
217
218 // Jump to the replacement section if check already in progress
220 body.add(goto_programt::make_skip(wrapper_symbol.location));
222
223 if(allow_recursive_calls)
224 {
231 body,
232 function_pointer_contracts);
233 }
234 else
235 {
236 source_locationt sl(wrapper_symbol.location);
237 sl.set_function(wrapper_symbol.name);
238 sl.set_property_class("no_recursive_call");
239 sl.set_comment(
240 "No recursive call to function " + id2string(function_id) +
241 " when checking contract " + id2string(contract_id));
243 body.add(
244 goto_programt::make_assumption(false_exprt(), wrapper_symbol.location));
245 }
246
247 auto end_function_label =
248 body.add(goto_programt::make_end_function(wrapper_symbol.location));
250
251 // write the body to the GOTO function
252 goto_model.goto_functions.function_map.at(function_id).body.swap(body);
253
254 // extend the signature of the wrapper function with the write set parameter
256
258
259 // instrument the wrapped function
261 wrapped_id, wrapper_id, loop_contract_config, function_pointer_contracts);
262
264}
265
267 const irep_idt &function_id,
268 const irep_idt &contract_id,
269 std::set<irep_idt> &function_pointer_contracts)
270{
271 const irep_idt &wrapper_id = function_id;
272 const irep_idt wrapped_id =
273 id2string(function_id) + "_wrapped_for_replacement_with_contract";
275
278 function_id,
279 "__write_set_to_check",
281
282 goto_programt body;
283
290 body,
291 function_pointer_contracts);
292
295 .location));
296
298
299 // write the body to the GOTO function
300 goto_model.goto_functions.function_map.at(function_id).body.swap(body);
301
302 // extend the signature with the new write set parameter
304}
ait supplies three of the four components needed: an abstract interpreter (in this case handling func...
Definition ai.h:562
The Boolean type.
Definition std_types.h:36
A contract is represented by a function declaration or definition with contract clauses attached to i...
void add_contract_instructions(const dfcc_contract_modet contract_mode, const irep_idt &wrapper_id, const irep_idt &wrapped_id, const irep_idt &contract_id, const symbolt &wrapper_write_set_symbol, goto_programt &dest, std::set< irep_idt > &function_pointer_contracts)
Adds instructions in dest modeling contract checking, assuming that ret_t wrapper_id(params) is the f...
This class instruments GOTO functions or instruction sequences for frame condition checking and loop ...
void instrument_wrapped_function(const irep_idt &wrapped_function_id, const irep_idt &initial_function_id, const loop_contract_configt &loop_contract_config, std::set< irep_idt > &function_pointer_contracts)
Instruments a GOTO function by adding an extra write set parameter and inserting frame condition chec...
Class interface to library types and functions defined in cprover_contracts.c.
std::map< dfcc_typet, typet > dfcc_type
Maps enum values to the actual types (dynamically loaded)
This class rewrites GOTO functions that use the built-ins:
void check_contract(const loop_contract_configt &loop_contract_config, const irep_idt &function_id, const irep_idt &contract_id, std::set< irep_idt > &function_pointer_contracts, bool allow_recursive_calls)
Swaps-and-wraps the given function_id in a wrapper function that checks the given contract_id.
dfcc_libraryt & library
dfcc_swap_and_wrapt(goto_modelt &goto_model, message_handlert &message_handler, dfcc_libraryt &library, dfcc_instrumentt &instrument, dfcc_spec_functionst &spec_functions, dfcc_contract_handlert &contract_handler)
void get_swapped_functions(std::set< irep_idt > &dest) const
Adds the set of swapped functions to dest.
static std::map< irep_idt, std::pair< irep_idt, std::pair< dfcc_contract_modet, loop_contract_configt > > > cache
remember all functions that were swapped/wrapped and in which mode
dfcc_instrumentt & instrument
dfcc_contract_handlert & contract_handler
void replace_with_contract(const irep_idt &function_id, const irep_idt &contract_id, std::set< irep_idt > &function_pointer_contracts)
Swaps-and-wraps the given function_id in a wrapper function that models the abstract behaviour of con...
void swap_and_wrap(const dfcc_contract_modet contract_mode, const loop_contract_configt &loop_contract_config, const irep_idt &function_id, const irep_idt &contract_id, std::set< irep_idt > &function_pointer_contracts, bool allow_recursive_calls)
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition dstring.h:38
The Boolean constant false.
Definition std_expr.h:3200
function_mapt function_map
symbol_tablet symbol_table
Symbol table.
Definition goto_model.h:31
goto_functionst goto_functions
GOTO functions.
Definition goto_model.h:34
A generic container class for the GOTO intermediate representation of one function.
static instructiont make_assumption(const exprt &g, const source_locationt &l=source_locationt::nil())
static instructiont make_end_function(const source_locationt &l=source_locationt::nil())
static instructiont make_assignment(const code_assignt &_code, const source_locationt &l=source_locationt::nil())
Create an assignment instruction.
static instructiont make_skip(const source_locationt &l=source_locationt::nil())
targett add(instructiont &&instruction)
Adds a given instruction at the end.
static instructiont make_assertion(const exprt &g, const source_locationt &l=source_locationt::nil())
static instructiont make_incomplete_goto(const exprt &_cond, const source_locationt &l=source_locationt::nil())
Thrown when user-provided input cannot be processed.
Boolean negation.
Definition std_expr.h:2459
The Boolean constant true.
Definition std_expr.h:3191
Specialisation of dfcc_contract_handlert for contracts.
std::string dfcc_contract_mode_to_string(const dfcc_contract_modet mode)
dfcc_contract_modet
Enum type representing the contract checking and replacement modes.
Add instrumentation to a goto program to perform frame condition checks.
Dynamic frame condition checking library loading.
@ CAR_SET_PTR
type of pointers to sets of CAR
Given a function_id and contract_id, swaps its body to a function with a fresh mangled name,...
Dynamic frame condition checking utility functions.
const std::string & id2string(const irep_idt &d)
Definition irep.h:44
double log(double x)
Definition math.c:2449
Program Transformation.
static symbolt & get_function_symbol(symbol_table_baset &, const irep_idt &function_id)
Returns the symbolt for function_id.
static const symbolt & create_new_parameter_symbol(symbol_table_baset &, const irep_idt &function_id, const std::string &base_name, const typet &type)
Creates a new parameter symbol for the given function_id.
static void wrap_function(goto_modelt &goto_model, const irep_idt &function_id, const irep_idt &wrapped_function_id)
Given a function to wrap foo and a new name wrapped_foo
static const symbolt & create_static_symbol(symbol_table_baset &, const typet &type, const std::string &prefix, const std::string &base_name, const source_locationt &source_location, const irep_idt &mode, const irep_idt &module, const exprt &initial_value, const bool no_nondet_initialization=true)
Adds a new static symbol named prefix::base_name of type type with value initial_value in the symbol ...
static void add_parameter(goto_modelt &, const symbolt &symbol, const irep_idt &function_id)
Adds the given symbol as parameter to the function symbol's code_type.
Loop contract configurations.
std::string to_string() const
dstringt irep_idt