CBMC
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
memory_snapshot_harness_generator.cpp
Go to the documentation of this file.
1/******************************************************************\
2
3Module: Harness to initialise memory from memory snapshot
4
5Author: Daniel Poetzl
6
7\******************************************************************/
8
10
11#include <util/arith_tools.h>
12#include <util/c_types.h>
14#include <util/fresh_symbol.h>
15#include <util/string2int.h>
16#include <util/string_utils.h>
17#include <util/symbol_table.h>
18
20
23#include <json/json_parser.h>
24
26
27#include <algorithm>
28
30 const std::string &option,
31 const std::list<std::string> &values)
32{
33 auto &require_exactly_one_value =
36 {
37 // the option belongs to recursive initialization
38 }
40 {
42 values.begin(), values.end());
43 }
45 {
46 for(auto const &array_size_pair : values)
47 {
48 try
49 {
50 std::string array;
51 std::string size;
52 split_string(array_size_pair, ':', array, size);
53 // --associated-array-size implies --treat-pointer-as-array
54 // but it is not an error to specify both, so we don't check
55 // for duplicates here
57 array);
58 auto const inserted =
61 if(!inserted.second)
62 {
64 "can not have two associated array sizes for one array",
66 }
67 }
68 catch(const deserialization_exceptiont &)
69 {
71 "'" + array_size_pair +
72 "' is in an invalid format for array size pair",
74 "array_name:size_name, where both are the names of global "
75 "variables"};
76 }
77 }
78 }
80 {
81 memory_snapshot_file = require_exactly_one_value(option, values);
82 }
84 {
85 initial_goto_location_line = require_exactly_one_value(option, values);
86 }
88 {
89 std::vector<std::string> havoc_candidates =
90 split_string(values.front(), ',', true);
91 for(const auto &candidate : havoc_candidates)
92 {
94 }
95 }
97 {
98 initial_source_location_line = require_exactly_one_value(option, values);
99 }
100 else
101 {
103 "unrecognized option for memory snapshot harness generator",
104 "--" + option);
105 }
106}
107
109 const goto_modelt &goto_model)
110{
111 if(memory_snapshot_file.empty())
112 {
114 "option --memory_snapshot is required",
115 "--harness-type initialize-with-memory-snapshot");
116 }
117
119 {
121 "choose either source or goto location to specify the entry point",
122 "--initial-source/goto-location");
123 }
124
126 {
129 goto_model.goto_functions);
130 }
131 else
132 {
135 goto_model.goto_functions);
136 }
137
138 const symbol_table_baset &symbol_table = goto_model.symbol_table;
139
141 symbol_table.lookup(entry_location.function_name);
142
143 if(called_function_symbol == nullptr)
144 {
146 "function `" + id2string(entry_location.function_name) +
147 "` not found in the symbol table",
148 "--initial-location");
149 }
150}
151
154 goto_modelt &goto_model) const
155{
156 goto_functionst &goto_functions = goto_model.goto_functions;
157
158 goto_functiont &goto_function =
160
161 goto_programt &goto_program = goto_function.body;
162
164 goto_program.instructions.begin();
165
166 auto ins_it1 = goto_program.insert_before(
167 start_it,
170
171 auto ins_it2 = goto_program.insert_after(
172 ins_it1,
175
176 goto_program.compute_location_numbers();
177 goto_program.insert_after(
178 ins_it2,
181}
182
185 symbol_table_baset &symbol_table) const
186{
188 snapshot_symbol.type,
189 "", // no prefix name
190 id2string(snapshot_symbol.base_name),
191 snapshot_symbol.location,
192 snapshot_symbol.mode,
193 symbol_table);
194 tmp_symbol.is_static_lifetime = true;
195 tmp_symbol.value = snapshot_symbol.value;
196
197 return tmp_symbol;
198}
199
201{
202 if(t.id() != ID_pointer)
203 return 0;
204 else
205 return pointer_depth(to_pointer_type(t).base_type()) + 1;
206}
207
210 goto_modelt &goto_model) const
211{
212 recursive_initializationt recursive_initialization{
214
215 std::vector<std::pair<irep_idt, symbolt>> ordered_snapshot_symbols;
216 // sort the snapshot symbols so that the non-pointer symbols are first, then
217 // pointers, then pointers-to-pointers, etc. so that we don't assign
218 // uninitialized values
219 {
220 std::vector<std::pair<irep_idt, symbolt>> selected_snapshot_symbols;
221 using relationt = typename preordert<irep_idt>::relationt;
222 relationt reference_relation;
223
224 for(const auto &snapshot_pair : snapshot)
225 {
226 const auto name = id2string(snapshot_pair.first);
227 if(name.find(CPROVER_PREFIX) != 0)
228 {
230 snapshot_pair.second.value,
232 reference_relation.insert(std::make_pair(snapshot_pair.first, id));
233 });
235 }
236 }
239 }
240
241 code_blockt code{};
242
243 // add initialization for existing globals
244 for(const auto &pair : goto_model.symbol_table)
245 {
246 const auto &global_symbol = pair.second;
248 {
249 auto symeexr = global_symbol.symbol_expr();
250 if(symeexr.type() == global_symbol.value.type())
251 code.add(code_assignt{symeexr, global_symbol.value});
252 }
253 }
254
255 for(const auto &pair : ordered_snapshot_symbols)
256 {
257 const symbolt &snapshot_symbol = pair.second;
258 symbol_table_baset &symbol_table = goto_model.symbol_table;
259
260 auto should_get_fresh = [&symbol_table](const symbolt &symbol) {
261 return symbol_table.lookup(symbol.base_name) == nullptr &&
262 !symbol.is_type;
263 };
266 ? fresh_symbol_copy(snapshot_symbol, symbol_table)
268
271 continue;
272
273 if(variables_to_havoc.count(fresh_or_snapshot_symbol.base_name) == 0)
274 {
275 code.add(code_assignt{fresh_or_snapshot_symbol.symbol_expr(),
277 }
278 else
279 {
280 recursive_initialization.initialize(
281 fresh_or_snapshot_symbol.symbol_expr(),
283 code);
284 }
285 }
286 return code;
287}
288
291 code_blockt &code) const
292{
294
296
297 for(const code_typet::parametert &parameter : code_type.parameters())
298 {
299 arguments.push_back(side_effect_expr_nondett{
300 parameter.type(), called_function_symbol.location});
301 }
302
304 std::move(arguments)});
305}
306
309 goto_modelt &goto_model,
310 const symbolt &function) const
311{
312 const auto r = goto_model.symbol_table.insert(function);
313 CHECK_RETURN(r.second);
314
315 auto function_iterator_pair = goto_model.goto_functions.function_map.emplace(
316 function.name, goto_functiont{});
317
319
321
323 goto_model.symbol_table, goto_model.goto_functions, message_handler);
325}
326
328 const std::string &file,
330{
331 jsont json;
332
334
335 if(r)
336 {
337 throw deserialization_exceptiont("failed to read JSON memory snapshot");
338 }
339
340 if(json.is_array())
341 {
342 // since memory-analyzer produces an array JSON we need to search it
343 // to find the first JSON object that is a symbol table
344 const auto &jarr = to_json_array(json);
345 for(auto const &arr_element : jarr)
346 {
347 if(!arr_element.is_object())
348 continue;
349 const auto &json_obj = to_json_object(arr_element);
350 const auto it = json_obj.find("symbolTable");
351 if(it != json_obj.end())
352 {
354 return;
355 }
356 }
358 "JSON memory snapshot does not contain symbol table");
359 }
360 else
361 {
362 // throws a deserialization_exceptiont or an
363 // incorrect_goto_program_exceptiont
364 // on failure to read JSON symbol table
366 }
367}
368
370 goto_modelt &goto_model,
371 const irep_idt &harness_function_name)
372{
375
376 symbol_tablet &symbol_table = goto_model.symbol_table;
377 goto_functionst &goto_functions = goto_model.goto_functions;
378
380 symbol_table.lookup(entry_location.function_name);
382
383 // introduce a symbol for a Boolean variable to indicate the point at which
384 // the function initialisation is completed
386 bool_typet(),
388 "func_init_done",
391 symbol_table);
392 func_init_done_symbol.is_static_lifetime = true;
395
397
400
402
405
406 // Create harness function symbol
407
409 harness_function_name,
410 code_typet({}, empty_typet()),
412 harness_function_symbol.base_name = harness_function_name;
413 harness_function_symbol.pretty_name = harness_function_name;
414 harness_function_symbol.is_lvalue = true;
416
417 // Add harness function to goto model and symbol table
419
420 goto_functions.update();
421}
422
425 const std::string &cmdl_option)
426{
427 std::vector<std::string> start = split_string(cmdl_option, ':', true);
428
429 if(
430 start.empty() || start.front().empty() ||
431 (start.size() == 2 && start.back().empty()) || start.size() > 2)
432 {
434 "invalid initial location specification", "--initial-location");
435 }
436
437 if(start.size() == 2)
438 {
439 const auto location_number = string2optional_unsigned(start.back());
440 CHECK_RETURN(location_number.has_value());
441 return entry_goto_locationt{start.front(), *location_number};
442 }
443 else
444 {
445 return entry_goto_locationt{start.front()};
446 }
447}
448
451 const std::string &cmdl_option)
452{
453 std::string initial_file_string;
454 std::string initial_line_string;
457
458 if(initial_file_string.empty() || initial_line_string.empty())
459 {
461 "invalid initial location specification", "--initial-file-line");
462 }
463
464 const auto line_number = string2optional_unsigned(initial_line_string);
465 CHECK_RETURN(line_number.has_value());
466 return entry_source_locationt{initial_file_string, *line_number};
467}
468
472 const goto_functionst &goto_functions)
473{
474 PRECONDITION(!entry_goto_location.function_name.empty());
475 const irep_idt &function_name = entry_goto_location.function_name;
476
477 // by function(+location): search for the function then jump to n-th
478 // location, then check the number
479 const auto &goto_function =
480 goto_functions.function_map.find(entry_goto_location.function_name);
481 if(
482 goto_function != goto_functions.function_map.end() &&
483 goto_function->second.body_available())
484 {
485 const auto &goto_program = goto_function->second.body;
486
487 const auto corresponding_instruction =
488 entry_goto_location.find_first_corresponding_instruction(
489 goto_program.instructions);
490
491 if(corresponding_instruction != goto_program.instructions.end())
492 return entry_locationt{function_name, corresponding_instruction};
493 }
495 "could not find the specified entry point", "--initial-goto-location");
496}
497
501 const goto_functionst &goto_functions)
502{
503 PRECONDITION(!entry_source_location.file_name.empty());
504
506 // by line: iterate over all instructions until source location match
507 for(const auto &entry : goto_functions.function_map)
508 {
509 const auto &goto_function = entry.second;
510 // if !body_available() then body.instruction.empty() and that's fine
511 const auto &goto_program = goto_function.body;
512
513 const auto candidate_instruction =
514 entry_source_location.find_first_corresponding_instruction(
515 goto_program.instructions);
516
517 if(candidate_instruction.first != goto_program.instructions.end())
518 {
519 best_match.match_up(
520 candidate_instruction.second, entry.first, candidate_instruction.first);
521 }
522 }
523
524 if(best_match.match_found)
525 return entry_locationt{best_match.function_name, best_match.instruction};
526 else
528 "could not find the specified entry point", "--initial-source-location");
529}
530
533 const goto_programt::instructionst &instructions) const
534{
535 if(!location_number.has_value())
536 return instructions.begin();
537
538 return std::find_if(
539 instructions.begin(),
540 instructions.end(),
541 [this](const goto_programt::instructiont &instruction) {
542 return *location_number == instruction.location_number;
543 });
544}
545
546std::pair<goto_programt::const_targett, size_t>
549 const goto_programt::instructionst &instructions) const
550{
551 auto it = std::find_if(
552 instructions.begin(),
553 instructions.end(),
554 [this](const goto_programt::instructiont &instruction) {
555 return instruction.source_location().get_file() == file_name &&
556 safe_string2unsigned(id2string(
557 instruction.source_location().get_line())) >= line_number;
558 });
559
560 if(it == instructions.end())
561 return {it, 0};
562 else
563 return {it,
564 safe_string2unsigned(id2string(it->source_location().get_line())) -
566}
constant_exprt from_integer(const mp_integer &int_value, const typet &type)
virtual void initialize(const irep_idt &function_id, const goto_programt &goto_program)
Initialize all the abstract states for a single function.
Definition ai.cpp:194
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 goto_instruction_codet representing an assignment in the program.
A codet representing sequential composition of program statements.
Definition std_code.h:130
void add(const codet &code)
Definition std_code.h:168
goto_instruction_codet representation of a function call statement.
Base type of functions.
Definition std_types.h:583
Thrown when failing to deserialize a value from some low level format, like JSON or raw bytes.
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
The Boolean constant false.
Definition std_expr.h:3199
A collection of goto functions.
function_mapt function_map
A goto function, consisting of function body (see body) and parameter identifiers (see parameter_iden...
goto_programt body
symbol_tablet symbol_table
Symbol table.
Definition goto_model.h:31
goto_functionst goto_functions
GOTO functions.
Definition goto_model.h:34
This class represents an instruction in the GOTO intermediate representation.
A generic container class for the GOTO intermediate representation of one function.
instructionst instructions
The list of instructions in the goto program.
targett const_cast_target(const_targett t)
Convert a const_targett to a targett - use with care and avoid whenever possible.
static instructiont make_end_function(const source_locationt &l=source_locationt::nil())
instructionst::const_iterator const_targett
static instructiont make_assignment(const code_assignt &_code, const source_locationt &l=source_locationt::nil())
Create an assignment instruction.
std::list< instructiont > instructionst
targett insert_after(const_targett target)
Insertion after the instruction pointed-to by the given instruction iterator target.
void compute_location_numbers(unsigned &nr)
Compute location numbers.
static instructiont make_goto(targett _target, const source_locationt &l=source_locationt::nil())
targett insert_before(const_targett target)
Insertion before the instruction pointed-to by the given instruction iterator target.
Thrown when users pass incorrect command line arguments, for example passing no files to analysis or ...
const irep_idt & id() const
Definition irep.h:388
Definition json.h:27
void add_init_section(const symbol_exprt &func_init_done_var, goto_modelt &goto_model) const
Modify the entry-point function to start from the user-specified initial location.
entry_locationt entry_location
data to initialize the entry function
void insert_harness_function_into_goto_model(goto_modelt &goto_model, const symbolt &function) const
Insert the function into the symbol table (and the goto functions map) of the goto_model.
const symbolt & fresh_symbol_copy(const symbolt &snapshot_symbol, symbol_table_baset &symbol_table) const
Introduce a new symbol into symbol_table with the same name and type as snapshot_symbol.
entry_locationt initialize_entry_via_goto(const entry_goto_locationt &entry_goto_location, const goto_functionst &goto_functions)
Find and return the entry instruction (requested by the user as goto location: function name + locati...
entry_source_locationt parse_source_location(const std::string &cmdl_option)
Parse a command line option to extract the user specified entry source location.
entry_locationt initialize_entry_via_source(const entry_source_locationt &entry_source_location, const goto_functionst &goto_functions)
Find and return the entry instruction (requested by the user as source location: file name + line num...
code_blockt add_assignments_to_globals(const symbol_table_baset &snapshot, goto_modelt &goto_model) const
For each global symbol in the snapshot symbol table either: 1) add code_assignt assigning a value fro...
void handle_option(const std::string &option, const std::list< std::string > &values) override
Collect the memory-snapshot specific cmdline options (one at a time)
entry_goto_locationt parse_goto_location(const std::string &cmdl_option)
Parse a command line option to extract the user specified entry goto location.
void collect_references(const exprt &expr, Adder &&add_reference) const
void generate(goto_modelt &goto_model, const irep_idt &harness_function_name) override
The main function of this harness, consists of the following:
void add_call_with_nondet_arguments(const symbolt &called_function_symbol, code_blockt &code) const
Create as many non-deterministic arguments as there are arguments of the called_function_symbol and a...
recursive_initialization_configt recursive_initialization_config
void get_memory_snapshot(const std::string &file, symbol_table_baset &snapshot) const
Parse the snapshot JSON file and initialise the symbol table.
void validate_options(const goto_modelt &goto_model) override
Check that user options make sense: On their own, e.g.
std::string memory_snapshot_file
data to store the command-line options
size_t pointer_depth(const typet &t) const
Recursively compute the pointer depth.
Class for generating initialisation code for compound structures.
static bool is_initialization_allowed(const symbolt &symbol)
A side_effect_exprt that returns a non-deterministically chosen value.
Definition std_code.h:1520
static const source_locationt & nil()
Expression to hold a symbol (variable)
Definition std_expr.h:131
The symbol table base class interface.
const symbolt * lookup(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
irep_idt name
The unique identifier.
Definition symbol.h:40
The Boolean constant true.
Definition std_expr.h:3190
The type of an expression, extends irept.
Definition type.h:29
#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.
void goto_convert(const codet &code, symbol_table_baset &symbol_table, goto_programt &dest, message_handlert &message_handler, const irep_idt &mode)
Goto Programs with Functions.
Symbol Table + CFG.
const std::string & id2string(const irep_idt &d)
Definition irep.h:44
static int8_t r
Definition irep_hash.h:60
json_objectt & to_json_object(jsont &json)
Definition json.h:442
json_arrayt & to_json_array(jsont &json)
Definition json.h:424
bool parse_json(std::istream &in, const std::string &filename, message_handlert &message_handler, jsont &dest)
void symbol_table_from_json(const jsont &in, symbol_table_baset &symbol_table)
#define MEMORY_SNAPSHOT_HARNESS_INITIAL_SOURCE_LOC_OPT
#define MEMORY_SNAPSHOT_HARNESS_HAVOC_VARIABLES_OPT
#define MEMORY_SNAPSHOT_HARNESS_ASSOCIATED_ARRAY_SIZE_OPT
#define MEMORY_SNAPSHOT_HARNESS_SNAPSHOT_OPT
#define MEMORY_SNAPSHOT_HARNESS_TREAT_POINTER_AS_ARRAY_OPT
#define MEMORY_SNAPSHOT_HARNESS_INITIAL_GOTO_LOC_OPT
std::string require_exactly_one_value(const std::string &option, const std::list< std::string > &values)
Returns the only value of a single element list, throws an exception if not passed a single element l...
const pointer_typet & to_pointer_type(const typet &type)
Cast a typet to a pointer_typet.
static void json(json_objectT &result, const irep_idt &property_id, const property_infot &property_info)
#define CHECK_RETURN(CONDITION)
Definition invariant.h:495
#define PRECONDITION(CONDITION)
Definition invariant.h:463
const code_typet & to_code_type(const typet &type)
Cast a typet to a code_typet.
Definition std_types.h:788
unsigned safe_string2unsigned(const std::string &str, int base)
std::optional< unsigned > string2optional_unsigned(const std::string &str, int base)
Convert string to unsigned similar to the stoul or stoull functions, return nullopt when the conversi...
void split_string(const std::string &s, char delim, std::vector< std::string > &result, bool strip, bool remove_empty)
User provided goto location: function name and (maybe) location number; the structure wraps this opti...
goto_programt::const_targett find_first_corresponding_instruction(const goto_programt::instructionst &instructions) const
Returns the first goto_programt::instructiont represented by this goto location, i....
Wraps the information needed to identify the entry point.
User provided source location: file name and line number; the structure wraps this option with a pars...
std::pair< goto_programt::const_targett, size_t > find_first_corresponding_instruction(const goto_programt::instructionst &instructions) const
Returns the first goto_programt::instructiont represented by this source location,...
Wraps the information for source location match candidates.
std::map< irep_idt, irep_idt > array_name_to_associated_array_size_variable
bool handle_option(const std::string &option, const std::list< std::string > &values)
Parse the options specific for recursive initialisation.
Author: Diffblue Ltd.
#define size_type
Definition unistd.c:186