CBMC
dfcc_swap_and_wrap.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: Dynamic frame condition checking
4 
5 Author: Remi Delmas, delmarsd@amazon.com
6 
7 \*******************************************************************/
8 
9 #include "dfcc_swap_and_wrap.h"
10 
11 #include <util/config.h>
12 #include <util/expr_util.h>
13 #include <util/format_expr.h>
14 #include <util/format_type.h>
15 #include <util/fresh_symbol.h>
16 #include <util/mathematical_expr.h>
18 #include <util/namespace.h>
19 #include <util/pointer_expr.h>
22 #include <util/std_expr.h>
23 
29 
30 #include <ansi-c/c_expr.h>
31 #include <ansi-c/cprover_library.h>
36 
38  goto_modelt &goto_model,
39  message_handlert &message_handler,
40  dfcc_libraryt &library,
41  dfcc_instrumentt &instrument,
42  dfcc_spec_functionst &spec_functions,
43  dfcc_contract_handlert &contract_handler)
44  : goto_model(goto_model),
45  message_handler(message_handler),
46  log(message_handler),
47  library(library),
48  instrument(instrument),
49  spec_functions(spec_functions),
50  contract_handler(contract_handler),
51  ns(goto_model.symbol_table)
52 {
53 }
54 
55 // static map
56 std::map<
57  irep_idt,
58  std::pair<irep_idt, std::pair<dfcc_contract_modet, dfcc_loop_contract_modet>>>
60 
62  const dfcc_contract_modet contract_mode,
63  const dfcc_loop_contract_modet loop_contract_mode,
64  const irep_idt &function_id,
65  const irep_idt &contract_id,
66  std::set<irep_idt> &function_pointer_contracts,
67  bool allow_recursive_calls)
68 {
69  auto pair = cache.insert(
70  {function_id, {contract_id, {contract_mode, loop_contract_mode}}});
71  auto inserted = pair.second;
72 
73  if(!inserted)
74  {
75  irep_idt old_contract_id = pair.first->second.first;
76  dfcc_contract_modet old_contract_mode = pair.first->second.second.first;
77  dfcc_loop_contract_modet old_loop_contract_mode =
78  pair.first->second.second.second;
79 
80  // different swap already performed, abort (should be unreachable)
81  if(
82  old_contract_id != contract_id || old_contract_mode != contract_mode ||
83  old_loop_contract_mode != loop_contract_mode)
84  {
85  std::ostringstream err_msg;
86  err_msg << "DFCC: multiple attempts to swap and wrap function '"
87  << function_id << "':\n";
88  err_msg << "- with '" << old_contract_id << "' in "
89  << dfcc_contract_mode_to_string(old_contract_mode) << " "
90  << dfcc_loop_contract_mode_to_string(old_loop_contract_mode)
91  << "\n";
92  err_msg << "- with '" << contract_id << "' in "
93  << dfcc_contract_mode_to_string(contract_mode) << " "
94  << dfcc_loop_contract_mode_to_string(loop_contract_mode) << "\n";
95  throw invalid_input_exceptiont(err_msg.str());
96  }
97  // same swap already performed
98  return;
99  }
100 
101  // actually perform the translation
102  switch(contract_mode)
103  {
105  {
107  loop_contract_mode,
108  function_id,
109  contract_id,
110  function_pointer_contracts,
111  allow_recursive_calls);
112  break;
113  }
115  {
116  replace_with_contract(function_id, contract_id, function_pointer_contracts);
117  break;
118  }
119  }
120 }
121 
122 void dfcc_swap_and_wrapt::get_swapped_functions(std::set<irep_idt> &dest) const
123 {
124  for(const auto &it : dfcc_swap_and_wrapt::cache)
125  {
126  dest.insert(it.first);
127  }
128 }
129 
155  const dfcc_loop_contract_modet loop_contract_mode,
156  const irep_idt &function_id,
157  const irep_idt &contract_id,
158  std::set<irep_idt> &function_pointer_contracts,
159  bool allow_recursive_calls)
160 {
161  // all code generation needs to run on functions with unmodified signatures
162  const irep_idt &wrapper_id = function_id;
163  const irep_idt wrapped_id =
164  id2string(wrapper_id) + "_wrapped_for_contract_checking";
165  dfcc_utilst::wrap_function(goto_model, wrapper_id, wrapped_id);
166 
167  // wrapper body
168  goto_programt body;
169 
170  const auto &wrapper_symbol =
172 
173  auto check_started = dfcc_utilst::create_static_symbol(
175  bool_typet(),
176  id2string(function_id),
177  "__contract_check_in_progress",
178  wrapper_symbol.location,
179  wrapper_symbol.mode,
180  wrapper_symbol.module,
181  false_exprt())
182  .symbol_expr();
183 
184  auto check_completed = dfcc_utilst::create_static_symbol(
186  bool_typet(),
187  id2string(function_id),
188  "__contract_checked_once",
189  wrapper_symbol.location,
190  wrapper_symbol.mode,
191  wrapper_symbol.module,
192  false_exprt())
193  .symbol_expr();
194 
195  auto check_started_goto = body.add(goto_programt::make_incomplete_goto(
196  check_started, wrapper_symbol.location));
197 
198  // At most a single top level call to the checked function in any execution
199 
200  // Recursive calls within a contract check correspond to
201  // `check_started && !check_completed` and are allowed.
202 
203  // Any other call occuring with `check_completed` true is forbidden.
204  source_locationt sl(wrapper_symbol.location);
205  sl.set_function(wrapper_symbol.name);
206  sl.set_property_class("single_top_level_call");
207  sl.set_comment(
208  "Only a single top-level call to function " + id2string(function_id) +
209  " when checking contract " + id2string(contract_id));
210  body.add(goto_programt::make_assertion(not_exprt(check_completed), sl));
212  check_started, true_exprt(), wrapper_symbol.location));
213 
214  const auto write_set_symbol = dfcc_utilst::create_new_parameter_symbol(
216  function_id,
217  "__write_set_to_check",
219 
222  wrapper_id,
223  wrapped_id,
224  contract_id,
225  write_set_symbol,
226  body,
227  function_pointer_contracts);
228 
230  check_completed, true_exprt(), wrapper_symbol.location));
232  check_started, false_exprt(), wrapper_symbol.location));
233 
234  // unconditionally Jump to the end after the check
235  auto goto_end_function =
236  body.add(goto_programt::make_incomplete_goto(wrapper_symbol.location));
237 
238  // Jump to the replacement section if check already in progress
239  auto contract_replacement_label =
240  body.add(goto_programt::make_skip(wrapper_symbol.location));
241  check_started_goto->complete_goto(contract_replacement_label);
242 
243  if(allow_recursive_calls)
244  {
247  wrapper_id,
248  wrapped_id,
249  contract_id,
250  write_set_symbol,
251  body,
252  function_pointer_contracts);
253  }
254  else
255  {
256  source_locationt sl(wrapper_symbol.location);
257  sl.set_function(wrapper_symbol.name);
258  sl.set_property_class("no_recursive_call");
259  sl.set_comment(
260  "No recursive call to function " + id2string(function_id) +
261  " when checking contract " + id2string(contract_id));
263  body.add(
264  goto_programt::make_assumption(false_exprt(), wrapper_symbol.location));
265  }
266 
267  auto end_function_label =
268  body.add(goto_programt::make_end_function(wrapper_symbol.location));
269  goto_end_function->complete_goto(end_function_label);
270 
271  // write the body to the GOTO function
272  goto_model.goto_functions.function_map.at(function_id).body.swap(body);
273 
274  // extend the signature of the wrapper function with the write set parameter
275  dfcc_utilst::add_parameter(goto_model, write_set_symbol, function_id);
276 
277  goto_model.goto_functions.function_map.at(wrapper_id).make_hidden();
278 
279  // instrument the wrapped function
281  wrapped_id, wrapper_id, loop_contract_mode, function_pointer_contracts);
282 
284 }
285 
287  const irep_idt &function_id,
288  const irep_idt &contract_id,
289  std::set<irep_idt> &function_pointer_contracts)
290 {
291  const irep_idt &wrapper_id = function_id;
292  const irep_idt wrapped_id =
293  id2string(function_id) + "_wrapped_for_replacement_with_contract";
294  dfcc_utilst::wrap_function(goto_model, function_id, wrapped_id);
295 
296  const auto write_set_symbol = dfcc_utilst::create_new_parameter_symbol(
298  function_id,
299  "__write_set_to_check",
301 
302  goto_programt body;
303 
306  wrapper_id,
307  wrapped_id,
308  contract_id,
309  write_set_symbol,
310  body,
311  function_pointer_contracts);
312 
315  .location));
316 
317  goto_model.goto_functions.function_map.at(wrapper_id).make_hidden();
318 
319  // write the body to the GOTO function
320  goto_model.goto_functions.function_map.at(function_id).body.swap(body);
321 
322  // extend the signature with the new write set parameter
323  dfcc_utilst::add_parameter(goto_model, write_set_symbol, function_id);
324 }
API to expression classes that are internal to the C frontend.
Classes providing CFG-based information about symbols to guide simplifications in function and loop a...
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 dfcc_loop_contract_modet loop_contract_mode, 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.
Definition: dfcc_library.h:154
std::map< dfcc_typet, typet > dfcc_type
Maps enum values to the actual types (dynamically loaded)
Definition: dfcc_library.h:214
This class rewrites GOTO functions that use the built-ins:
goto_modelt & goto_model
void swap_and_wrap(const dfcc_contract_modet contract_mode, const dfcc_loop_contract_modet loop_contract_mode, const irep_idt &function_id, const irep_idt &contract_id, std::set< irep_idt > &function_pointer_contracts, bool allow_recursive_calls)
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.
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...
static std::map< irep_idt, std::pair< irep_idt, std::pair< dfcc_contract_modet, dfcc_loop_contract_modet > > > cache
remember all functions that were swapped/wrapped and in which mode
void check_contract(const dfcc_loop_contract_modet loop_contract_mode, 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.
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:3064
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.
Definition: goto_program.h:73
static instructiont make_assumption(const exprt &g, const source_locationt &l=source_locationt::nil())
Definition: goto_program.h:945
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())
Definition: goto_program.h:891
targett add(instructiont &&instruction)
Adds a given instruction at the end.
Definition: goto_program.h:739
static instructiont make_assertion(const exprt &g, const source_locationt &l=source_locationt::nil())
Definition: goto_program.h:933
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:2327
void set_comment(const irep_idt &comment)
void set_property_class(const irep_idt &property_class)
void set_function(const irep_idt &function)
source_locationt location
Source code location of definition of symbol.
Definition: symbol.h:37
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:3055
std::string dfcc_contract_mode_to_string(const dfcc_contract_modet mode)
dfcc_contract_modet
Enum type representing the contract checking and replacement modes.
@ CAR_SET_PTR
type of pointers to sets of CAR
std::string dfcc_loop_contract_mode_to_string(const dfcc_loop_contract_modet mode)
dfcc_loop_contract_modet
Enumeration representing the instrumentation mode for loop contracts.
Given a function_id and contract_id, swaps its body to a function with a fresh mangled name,...
Deprecated expression utility functions.
Fresh auxiliary symbol creation.
Goto Programs with Functions.
Function Inlining This gives a number of different interfaces to the function inlining functionality ...
Symbol Table + CFG.
const std::string & id2string(const irep_idt &d)
Definition: irep.h:40
double log(double x)
Definition: math.c:2776
API to expression classes for 'mathematical' expressions.
Mathematical types.
API to expression classes for Pointers.
Pointer Logic.
Various predicates over pointers in programs.
Program Transformation.
API to expression classes.
static symbolt & get_function_symbol(symbol_table_baset &, const irep_idt &function_id)
Returns the symbolt for function_id.
Definition: dfcc_utils.cpp:72
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.
Definition: dfcc_utils.cpp:124
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
Definition: dfcc_utils.cpp:324
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 ...
Definition: dfcc_utils.cpp:103
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.
Definition: dfcc_utils.cpp:156
dstringt irep_idt