cprover
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
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;
58 loop_contract_configt old_loop_contract_config =
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 "
70 << dfcc_contract_mode_to_string(old_contract_mode) << " "
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";
75 throw invalid_input_exceptiont(err_msg.str());
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,
89 contract_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";
145 dfcc_utilst::wrap_function(goto_model, wrapper_id, wrapped_id);
146
147 // wrapper body
148 goto_programt body;
149
150 const auto &wrapper_symbol =
151 dfcc_utilst::get_function_symbol(goto_model.symbol_table, wrapper_id);
152
153 auto check_started = dfcc_utilst::create_static_symbol(
154 goto_model.symbol_table,
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
164 auto check_completed = dfcc_utilst::create_static_symbol(
165 goto_model.symbol_table,
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
175 auto check_started_goto = body.add(goto_programt::make_incomplete_goto(
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));
190 body.add(goto_programt::make_assertion(not_exprt(check_completed), sl));
192 check_started, true_exprt(), wrapper_symbol.location));
193
194 const auto write_set_symbol = dfcc_utilst::create_new_parameter_symbol(
195 goto_model.symbol_table,
196 function_id,
197 "__write_set_to_check",
199
200 contract_handler.add_contract_instructions(
202 wrapper_id,
203 wrapped_id,
204 contract_id,
205 write_set_symbol,
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
219 auto contract_replacement_label =
220 body.add(goto_programt::make_skip(wrapper_symbol.location));
221 check_started_goto->complete_goto(contract_replacement_label);
222
223 if(allow_recursive_calls)
224 {
225 contract_handler.add_contract_instructions(
227 wrapper_id,
228 wrapped_id,
229 contract_id,
230 write_set_symbol,
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));
249 goto_end_function->complete_goto(end_function_label);
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
255 dfcc_utilst::add_parameter(goto_model, write_set_symbol, function_id);
256
257 goto_model.goto_functions.function_map.at(wrapper_id).make_hidden();
258
259 // instrument the wrapped function
260 instrument.instrument_wrapped_function(
261 wrapped_id, wrapper_id, loop_contract_config, function_pointer_contracts);
262
263 goto_model.goto_functions.update();
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";
274 dfcc_utilst::wrap_function(goto_model, function_id, wrapped_id);
275
276 const auto write_set_symbol = dfcc_utilst::create_new_parameter_symbol(
277 goto_model.symbol_table,
278 function_id,
279 "__write_set_to_check",
281
282 goto_programt body;
283
284 contract_handler.add_contract_instructions(
286 wrapper_id,
287 wrapped_id,
288 contract_id,
289 write_set_symbol,
290 body,
291 function_pointer_contracts);
292
294 dfcc_utilst::get_function_symbol(goto_model.symbol_table, wrapper_id)
295 .location));
296
297 goto_model.goto_functions.function_map.at(wrapper_id).make_hidden();
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
303 dfcc_utilst::add_parameter(goto_model, write_set_symbol, function_id);
304}
The Boolean type.
Definition std_types.h:36
A contract is represented by a function declaration or definition with contract clauses attached to i...
This class instruments GOTO functions or instruction sequences for frame condition checking and loop ...
Class interface to library types and functions defined in cprover_contracts.c.
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.
message_handlert & message_handler
dfcc_spec_functionst & spec_functions
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)
The Boolean constant false.
Definition std_expr.h:3246
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
void set_comment(const irep_idt &comment)
void set_property_class(const irep_idt &property_class)
void set_function(const irep_idt &function)
class symbol_exprt symbol_expr() const
Produces a symbol_exprt for a symbol.
Definition symbol.cpp:121
The Boolean constant true.
Definition std_expr.h:3237
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
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