CBMC
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
generate_function_bodies.cpp
Go to the documentation of this file.
1/*******************************************************************\
2
3Module: Replace bodies of goto functions
4
5Author: Diffblue Ltd.
6
7\*******************************************************************/
8
10
11#include <util/fresh_symbol.h>
12#include <util/pointer_expr.h>
13#include <util/prefix.h>
14#include <util/string2int.h>
15#include <util/string_utils.h>
16
19
23
25 goto_functiont &function,
26 symbol_tablet &symbol_table,
27 const irep_idt &function_name) const
28{
29 PRECONDITION(!function.body_available());
30 generate_parameter_names(function, symbol_table, function_name);
31 generate_function_body_impl(function, symbol_table, function_name);
32}
33
35 goto_functiont &function,
36 symbol_tablet &symbol_table,
37 const irep_idt &function_name) const
38{
39 auto &function_symbol = symbol_table.get_writeable_ref(function_name);
40 auto &parameters = to_code_type(function_symbol.type).parameters();
41
42 int param_counter = 0;
43 for(auto &parameter : parameters)
44 {
45 if(parameter.get_identifier().empty())
46 {
47 const std::string param_base_name =
48 parameter.get_base_name().empty()
49 ? "__param$" + std::to_string(param_counter++)
50 : id2string(parameter.get_base_name());
52 id2string(function_name) + "::" + param_base_name;
53 parameter.set_base_name(param_base_name);
54 parameter.set_identifier(new_param_identifier);
57 new_param_sym.type = parameter.type();
60 new_param_sym.module = function_symbol.module;
61 new_param_sym.location = function_symbol.location;
62 symbol_table.add(new_param_sym);
63 }
64 }
66}
67
69{
70protected:
72 goto_functiont &function,
73 symbol_tablet &symbol_table,
74 const irep_idt &function_name) const override
75 {
76 auto const &function_symbol = symbol_table.lookup_ref(function_name);
77 source_locationt location = function_symbol.location;
78 location.set_function(function_name);
79
81 function.body.add(goto_programt::make_end_function(location));
82 }
83};
84
86{
87protected:
89 goto_functiont &function,
90 symbol_tablet &symbol_table,
91 const irep_idt &function_name) const override
92 {
93 auto const &function_symbol = symbol_table.lookup_ref(function_name);
94
96 annotated_location.set_function(function_name);
97 annotated_location.set_comment("undefined function should be unreachable");
98 annotated_location.set_property_class(ID_assertion);
99 function.body.add(
101
102 source_locationt location = function_symbol.location;
103 location.set_function(function_name);
104 function.body.add(goto_programt::make_end_function(location));
105 }
106};
107
110{
111protected:
113 goto_functiont &function,
114 symbol_tablet &symbol_table,
115 const irep_idt &function_name) const override
116 {
117 auto const &function_symbol = symbol_table.lookup_ref(function_name);
118
120 annotated_location.set_function(function_name);
121 annotated_location.set_comment("undefined function should be unreachable");
122 annotated_location.set_property_class(ID_assertion);
123 function.body.add(
125
126 source_locationt location = function_symbol.location;
127 location.set_function(function_name);
128 function.body.add(goto_programt::make_assumption(false_exprt(), location));
129 function.body.add(goto_programt::make_end_function(location));
130 }
131};
132
134{
135public:
148
161
162private:
164 const exprt &lhs,
165 const std::size_t initial_depth,
166 const source_locationt &source_location,
167 const irep_idt &function_id,
168 symbol_tablet &symbol_table,
169 goto_programt &dest) const
170 {
172 symbol_table,
173 source_location,
174 function_id,
177
178 code_blockt assignments;
179
180 symbol_factory.gen_nondet_init(
181 assignments,
182 lhs,
185 false); // do not initialize const objects at the top level
186
188
189 symbol_factory.declare_created_symbols(init_code);
190 init_code.append(assignments);
191
195
197 }
198
200 const std::string &param_name,
201 std::size_t param_number) const
202 {
203 if(parameters_to_havoc.has_value())
204 {
205 return std::regex_match(param_name, *parameters_to_havoc);
206 }
207 else
208 {
210 return std::binary_search(
211 param_numbers_to_havoc->begin(),
214 }
215 }
216
217protected:
219 goto_functiont &function,
220 symbol_tablet &symbol_table,
221 const irep_idt &function_name) const override
222 {
223 const namespacet ns(symbol_table);
224 // some user input checking
225 if(param_numbers_to_havoc.has_value() && !param_numbers_to_havoc->empty())
226 {
227 auto max_param_number = std::max_element(
229 if(*max_param_number >= function.parameter_identifiers.size())
230 {
232 "function " + id2string(function_name) + " does not take " +
233 std::to_string(*max_param_number + 1) + " arguments",
234 "--generate-havocing-body"};
235 }
236 for(const auto number : *param_numbers_to_havoc)
237 {
238 const auto &parameter = function.parameter_identifiers[number];
240 if(parameter_symbol.type.id() != ID_pointer)
241 {
243 "argument number " + std::to_string(number) + " of function " +
244 id2string(function_name) + " is not a pointer",
245 "--generate-havocing-body"};
246 }
247 }
248 }
249
250 auto const &function_symbol = symbol_table.lookup_ref(function_name);
251 source_locationt location = function_symbol.location;
252 location.set_function(function_name);
253
254 for(std::size_t i = 0; i < function.parameter_identifiers.size(); ++i)
255 {
256 const auto &parameter = function.parameter_identifiers[i];
258 if(
259 parameter_symbol.type.id() == ID_pointer &&
261 .base_type()
262 .get_bool(ID_C_constant) &&
264 {
265 auto goto_instruction =
268 parameter_symbol.symbol_expr(),
270 location));
271
272 dereference_exprt dereference_expr(
273 parameter_symbol.symbol_expr(),
274 to_pointer_type(parameter_symbol.type).base_type());
275
276 goto_programt dest;
278 dereference_expr,
279 1, // depth 1 since we pass the dereferenced pointer
280 location,
281 function_name,
282 symbol_table,
283 dest);
284
285 function.body.destructive_append(dest);
286
287 auto label_instruction =
288 function.body.add(goto_programt::make_skip(location));
289 goto_instruction->complete_goto(label_instruction);
290 }
291 }
292
293 for(auto const &global_id : globals_to_havoc)
294 {
295 auto const &global_sym = symbol_table.lookup_ref(global_id);
296
297 goto_programt dest;
298
301 0,
302 location,
303 irep_idt(),
304 symbol_table,
305 dest);
306
307 function.body.destructive_append(dest);
308 }
309
310 const typet &return_type = to_code_type(function_symbol.type).return_type();
311 if(return_type != empty_typet())
312 {
313 typet type(return_type);
314 type.remove(ID_C_constant);
315
317 type,
318 id2string(function_name),
319 "return_value",
320 location,
321 ID_C,
322 symbol_table);
323
324 aux_symbol.is_static_lifetime = false;
325
326 function.body.add(
327 goto_programt::make_decl(aux_symbol.symbol_expr(), location));
328
329 goto_programt dest;
330
332 aux_symbol.symbol_expr(),
333 0,
334 location,
335 function_name,
336 symbol_table,
337 dest);
338
339 function.body.destructive_append(dest);
340
342 typecast_exprt::conditional_cast(aux_symbol.symbol_expr(), return_type);
343
344 function.body.add(
346
347 function.body.add(
348 goto_programt::make_dead(aux_symbol.symbol_expr(), location));
349 }
350
351 function.body.add(goto_programt::make_end_function(location));
352
353 remove_skip(function.body);
354 }
355
356private:
357 const std::vector<irep_idt> globals_to_havoc;
358 std::optional<std::regex> parameters_to_havoc;
359 std::optional<std::vector<std::size_t>> param_numbers_to_havoc;
362};
363
364class generate_function_bodies_errort : public std::runtime_error
365{
366public:
367 explicit generate_function_bodies_errort(const std::string &reason)
368 : runtime_error(reason)
369 {
370 }
371};
372
375std::unique_ptr<generate_function_bodiest> generate_function_bodies_factory(
376 const std::string &options,
377 const c_object_factory_parameterst &object_factory_parameters,
378 const symbol_tablet &symbol_table,
379 message_handlert &message_handler)
380{
381 if(options.empty() || options == "nondet-return")
382 {
383 return std::make_unique<havoc_generate_function_bodiest>(
384 std::vector<irep_idt>{},
385 std::regex{},
386 object_factory_parameters,
387 message_handler);
388 }
389
390 if(options == "assume-false")
391 {
392 return std::make_unique<assume_false_generate_function_bodiest>();
393 }
394
395 if(options == "assert-false")
396 {
397 return std::make_unique<assert_false_generate_function_bodiest>();
398 }
399
400 if(options == "assert-false-assume-false")
401 {
402 return std::make_unique<
404 }
405
406 const std::vector<std::string> option_components = split_string(options, ',');
407 if(!option_components.empty() && option_components[0] == "havoc")
408 {
409 std::regex globals_regex;
410 std::regex params_regex;
411 std::vector<std::size_t> param_numbers;
412 for(std::size_t i = 1; i < option_components.size(); ++i)
413 {
414 const std::vector<std::string> key_value_pair =
416 if(key_value_pair.size() != 2)
417 {
419 "Expected key_value_pair of form argument:value");
420 }
421 if(key_value_pair[0] == "globals")
422 {
424 }
425 else if(key_value_pair[0] == "params")
426 {
428 if(param_identifiers.size() == 1)
429 {
432 if(!maybe_nondet_param_number.has_value())
433 {
435 continue;
436 }
437 }
438 std::transform(
439 param_identifiers.begin(),
440 param_identifiers.end(),
441 std::back_inserter(param_numbers),
442 [](const std::string &param_id) {
443 auto maybe_nondet_param_number = string2optional_size_t(param_id);
444 INVARIANT(
445 maybe_nondet_param_number.has_value(),
446 param_id + " not a number");
447 return *maybe_nondet_param_number;
448 });
449 std::sort(param_numbers.begin(), param_numbers.end());
450 }
451 else
452 {
454 "Unknown option \"" + key_value_pair[0] + "\"");
455 }
456 }
457 std::vector<irep_idt> globals_to_havoc;
458 namespacet ns(symbol_table);
459 messaget messages(message_handler);
460 const std::regex cprover_prefix = std::regex("__CPROVER.*");
461 for(auto const &symbol : symbol_table.symbols)
462 {
463 if(
464 symbol.second.is_lvalue && symbol.second.is_static_lifetime &&
465 std::regex_match(id2string(symbol.first), globals_regex))
466 {
467 if(std::regex_match(id2string(symbol.first), cprover_prefix))
468 {
469 messages.warning() << "generate function bodies: "
470 << "matched global '" << id2string(symbol.first)
471 << "' begins with __CPROVER, "
472 << "havoc-ing this global may interfere"
473 << " with analysis" << messaget::eom;
474 }
475 globals_to_havoc.push_back(symbol.first);
476 }
477 }
478 if(param_numbers.empty())
479 return std::make_unique<havoc_generate_function_bodiest>(
480 std::move(globals_to_havoc),
481 std::move(params_regex),
482 object_factory_parameters,
483 message_handler);
484 else
485 return std::make_unique<havoc_generate_function_bodiest>(
486 std::move(globals_to_havoc),
487 std::move(param_numbers),
488 object_factory_parameters,
489 message_handler);
490 }
491 throw generate_function_bodies_errort("Can't parse \"" + options + "\"");
492}
493
502 const std::regex &functions_regex,
503 const generate_function_bodiest &generate_function_body,
504 goto_modelt &model,
505 message_handlert &message_handler)
506{
507 messaget messages(message_handler);
508 const std::regex cprover_prefix = std::regex("__CPROVER.*");
509 bool did_generate_body = false;
510 for(auto &function : model.goto_functions.function_map)
511 {
512 if(
513 !function.second.body_available() &&
514 std::regex_match(id2string(function.first), functions_regex))
515 {
516 if(std::regex_match(id2string(function.first), cprover_prefix))
517 {
518 messages.warning() << "generate function bodies: matched function '"
519 << id2string(function.first)
520 << "' begins with __CPROVER "
521 << "the generated body for this function "
522 << "may interfere with analysis" << messaget::eom;
523 }
524 did_generate_body = true;
525 generate_function_body.generate_function_body(
526 function.second, model.symbol_table, function.first);
527 }
528 }
530 {
531 messages.warning()
532 << "generate function bodies: No function name matched regex"
533 << messaget::eom;
534 }
535}
536
538 const std::string &function_name,
539 const std::string &call_site_id,
540 const generate_function_bodiest &generate_function_body,
541 goto_modelt &model,
542 message_handlert &message_handler)
543{
544 PRECONDITION(!has_prefix(function_name, CPROVER_PREFIX));
546 PRECONDITION(call_site_number.has_value());
547
548 messaget messages(message_handler);
549
550 bool found = false;
552 typet function_type;
553
554 // get the mode and type from symbol table
555 for(auto const &symbol_pair : model.symbol_table)
556 {
557 auto const symbol = symbol_pair.second;
558 if(symbol.type.id() == ID_code && symbol.name == function_name)
559 {
560 function_mode = symbol.mode;
561 function_type = symbol.type;
562 found = true;
563 break;
564 }
565 }
567
568 // add function of the right name to the symbol table
571 havoc_function_symbol.pretty_name = function_name + "." + call_site_id;
572
573 havoc_function_symbol.is_lvalue = true;
575 havoc_function_symbol.type = function_type;
576
578
579 auto const &generated_havoc =
581
582 // convert to get the function stub to goto-model
583 goto_convert(model.symbol_table, model.goto_functions, message_handler);
584
585 // now generate body as above
586 for(auto &function : model.goto_functions.function_map)
587 {
588 if(
589 !function.second.body_available() &&
590 havoc_function_symbol.name == id2string(function.first))
591 {
592 generate_function_body.generate_function_body(
593 function.second, model.symbol_table, function.first);
594 }
595 }
596
597 auto is_havoc_function_call = [&function_name](const exprt &expr) {
598 if(expr.id() != ID_symbol)
599 return false;
600 std::string called_function_name =
601 id2string(to_symbol_expr(expr).get_identifier());
602 if(called_function_name == function_name)
603 return true;
604
605 return (has_prefix(called_function_name, function_name + "."));
606 };
607
608 // finally, rename the (right) call site
609 std::size_t counter = 0;
610 for(auto &function : model.goto_functions.function_map)
611 {
612 for(auto &instruction : function.second.body.instructions)
613 {
614 if(instruction.is_function_call())
615 {
616 auto &called_function = instruction.call_function();
617 if(is_havoc_function_call(called_function))
618 {
619 if(++counter == *call_site_number)
620 {
621 called_function = generated_havoc.symbol_expr();
622 return;
623 }
624 }
625 }
626 }
627 }
628}
@ DYNAMIC
Allocate dynamic objects (using ALLOCATE)
C Nondet Symbol Factory.
ait supplies three of the four components needed: an abstract interpreter (in this case handling func...
Definition ai.h:562
void generate_function_body_impl(goto_functiont &function, symbol_tablet &symbol_table, const irep_idt &function_name) const override
Produce a body for the passed function At this point the body of function is always empty,...
void generate_function_body_impl(goto_functiont &function, symbol_tablet &symbol_table, const irep_idt &function_name) const override
Produce a body for the passed function At this point the body of function is always empty,...
void generate_function_body_impl(goto_functiont &function, symbol_tablet &symbol_table, const irep_idt &function_name) const override
Produce a body for the passed function At this point the body of function is always empty,...
A codet representing sequential composition of program statements.
Definition std_code.h:130
Operator to dereference a pointer.
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition dstring.h:38
The empty type.
Definition std_types.h:51
Equality.
Definition std_expr.h:1366
Base class for all expressions.
Definition expr.h:56
The Boolean constant false.
Definition std_expr.h:3199
generate_function_bodies_errort(const std::string &reason)
Base class for replace_function_body implementations.
void generate_function_body(goto_functiont &function, symbol_tablet &symbol_table, const irep_idt &function_name) const
Replace the function body with one based on the replace_function_body class being used.
void generate_parameter_names(goto_functiont &function, symbol_tablet &symbol_table, const irep_idt &function_name) const
Generate parameter names for unnamed parameters.
virtual void generate_function_body_impl(goto_functiont &function, symbol_tablet &symbol_table, const irep_idt &function_name) const =0
Produce a body for the passed function At this point the body of function is always empty,...
function_mapt function_map
A goto function, consisting of function body (see body) and parameter identifiers (see parameter_iden...
goto_programt body
parameter_identifierst parameter_identifiers
The identifiers of the parameters of this function.
bool body_available() const
void set_parameter_identifiers(const code_typet &code_type)
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_set_return_value(exprt return_value, const source_locationt &l=source_locationt::nil())
static instructiont make_dead(const symbol_exprt &symbol, const source_locationt &l=source_locationt::nil())
static instructiont make_end_function(const source_locationt &l=source_locationt::nil())
void destructive_append(goto_programt &p)
Appends the given program p to *this. p is destroyed.
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_decl(const symbol_exprt &symbol, const source_locationt &l=source_locationt::nil())
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())
havoc_generate_function_bodiest(std::vector< irep_idt > globals_to_havoc, std::vector< std::size_t > param_numbers_to_havoc, const c_object_factory_parameterst &object_factory_parameters, message_handlert &message_handler)
std::optional< std::vector< std::size_t > > param_numbers_to_havoc
const std::vector< irep_idt > globals_to_havoc
havoc_generate_function_bodiest(std::vector< irep_idt > globals_to_havoc, std::regex parameters_to_havoc, const c_object_factory_parameterst &object_factory_parameters, message_handlert &message_handler)
bool should_havoc_param(const std::string &param_name, std::size_t param_number) const
std::optional< std::regex > parameters_to_havoc
void generate_function_body_impl(goto_functiont &function, symbol_tablet &symbol_table, const irep_idt &function_name) const override
Produce a body for the passed function At this point the body of function is always empty,...
const c_object_factory_parameterst & object_factory_parameters
void havoc_expr_rec(const exprt &lhs, const std::size_t initial_depth, const source_locationt &source_location, const irep_idt &function_id, symbol_tablet &symbol_table, goto_programt &dest) const
Thrown when users pass incorrect command line arguments, for example passing no files to analysis or ...
void remove(const irep_idt &name)
Definition irep.cpp:87
Class that provides messages with a built-in verbosity 'level'.
Definition message.h:154
message_handlert & get_message_handler()
Definition message.h:183
mstreamt & warning() const
Definition message.h:396
static eomt eom
Definition message.h:289
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
Definition namespace.h:91
bool lookup(const irep_idt &name, const symbolt *&symbol) const override
See documentation for namespace_baset::lookup().
The null pointer constant.
Symbol table entry of function parameterThis is a symbol generated as part of type checking.
Definition symbol.h:179
void set_function(const irep_idt &function)
Expression to hold a symbol (variable)
Definition std_expr.h:131
std::set< irep_idt > recursion_sett
symbolt & get_writeable_ref(const irep_idt &name)
Find a symbol in the symbol table for read-write access.
const symbolst & symbols
Read-only field, used to look up symbols given their names.
bool add(const symbolt &symbol)
Add a new symbol to the symbol table.
const symbolt & lookup_ref(const irep_idt &name) const
Find a symbol in the symbol table for read-only access.
The symbol table.
virtual std::pair< symbolt &, bool > insert(symbolt symbol) override
Author: Diffblue Ltd.
Symbol table entry.
Definition symbol.h:28
static exprt conditional_cast(const exprt &expr, const typet &type)
Definition std_expr.h:2081
The type of an expression, extends irept.
Definition type.h:29
bool has_prefix(const std::string &s, const std::string &prefix)
Definition converter.cpp:13
#define CPROVER_PREFIX
symbolt & get_fresh_aux_symbol(const typet &type, const std::string &name_prefix, const std::string &basename_prefix, const source_locationt &source_location, const irep_idt &symbol_mode, const namespacet &ns, symbol_table_baset &symbol_table)
Installs a fresh-named symbol with respect to the given namespace ns with the requested name pattern ...
Fresh auxiliary symbol creation.
std::unique_ptr< generate_function_bodiest > generate_function_bodies_factory(const std::string &options, const c_object_factory_parameterst &object_factory_parameters, const symbol_tablet &symbol_table, message_handlert &message_handler)
Create the type that actually generates the functions.
void generate_function_bodies(const std::regex &functions_regex, const generate_function_bodiest &generate_function_body, goto_modelt &model, message_handlert &message_handler)
Generate function bodies with some default behavior: assert-false, assume-false, assert-false-assume-...
void goto_convert(const codet &code, symbol_table_baset &symbol_table, goto_programt &dest, message_handlert &message_handler, const irep_idt &mode)
Program Transformation.
Goto Programs with Functions.
Symbol Table + CFG.
const std::string & id2string(const irep_idt &d)
Definition irep.h:44
STL namespace.
API to expression classes for Pointers.
const pointer_typet & to_pointer_type(const typet &type)
Cast a typet to a pointer_typet.
void remove_skip(goto_programt &goto_program, goto_programt::targett begin, goto_programt::targett end)
remove unnecessary skip statements
Program Transformation.
#define CHECK_RETURN(CONDITION)
Definition invariant.h:495
#define PRECONDITION(CONDITION)
Definition invariant.h:463
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast an exprt to a symbol_exprt.
Definition std_expr.h:272
const code_typet & to_code_type(const typet &type)
Cast a typet to a code_typet.
Definition std_types.h:788
std::optional< std::size_t > string2optional_size_t(const std::string &str, int base)
Convert string to size_t similar to the stoul or stoull functions, return nullopt when the conversion...
void split_string(const std::string &s, char delim, std::vector< std::string > &result, bool strip, bool remove_empty)