Skip to content

Commit f91ed60

Browse files
committed
Feature to initialize symex with memory snapshot and start from given location
This adds a feature to load a concrete memory snapshot (represented as a JSON symbol table) into cbmc to initialize goto symex with, and then start symex from a given program location. The path to the snapshot must be passed to --memory-snapshot and the initial program location must be specified via --initial-location. This is a basic first version that only supports the initialisation of global variables. Moreover, the concrete memory snapshot does not contain a representation of the stack of the program, hence symex must stop when it reaches the end of the function in which it was started (but it can go into callees and return from them).
1 parent 54a210d commit f91ed60

File tree

5 files changed

+191
-3
lines changed

5 files changed

+191
-3
lines changed

src/cbmc/bmc.cpp

Lines changed: 95 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,18 @@ Author: Daniel Kroening, [email protected]
2222
#include <goto-symex/show_program.h>
2323
#include <goto-symex/show_vcc.h>
2424

25+
#include <json/json_parser.h>
26+
27+
#include <json-symtab-language/json_symbol_table.h>
28+
2529
#include <linking/static_lifetime_init.h>
2630

2731
#include <goto-checker/bmc_util.h>
2832
#include <goto-checker/solver_factory.h>
2933

34+
#include <util/string2int.h>
35+
#include <util/string_utils.h>
36+
3037
#include "counterexample_beautification.h"
3138
#include "fault_localization.h"
3239

@@ -403,7 +410,94 @@ int bmct::do_language_agnostic_bmc(
403410
void bmct::perform_symbolic_execution(
404411
goto_symext::get_goto_functiont get_goto_function)
405412
{
406-
symex.symex_from_entry_point_of(get_goto_function, symex_symbol_table);
413+
if(options.is_set("memory-snapshot"))
414+
{
415+
// start symex from given program location and memory snapshot
416+
417+
INVARIANT(
418+
options.is_set("initial-location"),
419+
"during option parsing it should be checked that --initial-location is "
420+
"provided when --memory-snapshot is given");
421+
422+
jsont json;
423+
{
424+
const bool r = parse_json(
425+
options.get_option("memory-snapshot"), ui_message_handler, json);
426+
427+
if(r)
428+
{
429+
throw deserialization_exceptiont("failed to read JSON memory snapshot");
430+
}
431+
}
432+
433+
symbol_tablet snapshot;
434+
435+
// throws a deserialization_exceptiont on failure to read JSON symbol table
436+
symbol_table_from_json(json, snapshot);
437+
438+
std::vector<std::string> start;
439+
split_string(options.get_option("initial-location"), ':', start, true);
440+
441+
CHECK_RETURN(start.size() > 0);
442+
443+
if(start.front().empty() || start.size() > 2)
444+
{
445+
throw invalid_command_line_argument_exceptiont(
446+
"invalid initial location specification", "--initial-location");
447+
}
448+
449+
INVARIANT(
450+
!start.back().empty(),
451+
"component of initial location specification should not be empty");
452+
453+
const irep_idt function_id(start.front());
454+
455+
const goto_functionst::goto_functiont &goto_function =
456+
get_goto_function(function_id);
457+
458+
if(!goto_function.body_available())
459+
{
460+
throw invalid_command_line_argument_exceptiont(
461+
"starting function must have a body", "--initial-location");
462+
}
463+
464+
const goto_programt::instructionst &instructions =
465+
goto_function.body.instructions;
466+
467+
goto_programt::const_targett it = instructions.begin();
468+
469+
if(start.size() == 2)
470+
{
471+
// the initial location specification includes a location number
472+
473+
const unsigned location_number = safe_string2unsigned(start.back());
474+
475+
const unsigned start_location_number = it->location_number;
476+
const unsigned end_location_number =
477+
std::prev(instructions.end())->location_number;
478+
479+
INVARIANT(
480+
start_location_number <= end_location_number,
481+
"location numbers should be increasing in goto program");
482+
483+
if(
484+
location_number < start_location_number ||
485+
location_number > end_location_number)
486+
{
487+
throw invalid_command_line_argument_exceptiont(
488+
"location number does not exist in function", "--initial-location");
489+
}
490+
491+
std::advance(it, location_number - start_location_number);
492+
}
493+
494+
symex.symex_from_instruction_with_snapshot(
495+
get_goto_function, symex_symbol_table, snapshot, it);
496+
}
497+
else
498+
{
499+
symex.symex_from_entry_point_of(get_goto_function, symex_symbol_table);
500+
}
407501

408502
if(options.get_bool_option("validate-ssa-equation"))
409503
{

src/cbmc/cbmc_parse_options.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,33 @@ void cbmc_parse_optionst::get_command_line_options(optionst &options)
413413
options.set_option("validate-goto-model", true);
414414
}
415415

416+
{
417+
const bool memory_snapshot = cmdline.isset("memory-snapshot");
418+
const bool initial_location = cmdline.isset("initial-location");
419+
420+
if(memory_snapshot || initial_location)
421+
{
422+
if(!memory_snapshot)
423+
{
424+
throw invalid_command_line_argument_exceptiont(
425+
"--initial-location also requires --memory-snapshot",
426+
"--initial-location");
427+
}
428+
else if(!initial_location)
429+
{
430+
throw invalid_command_line_argument_exceptiont(
431+
"--memory-snapshot also requires --initial-location",
432+
"--memory-snapshot");
433+
}
434+
435+
options.set_option(
436+
"memory-snapshot", cmdline.get_value("memory-snapshot"));
437+
438+
options.set_option(
439+
"initial-location", cmdline.get_value("initial-location"));
440+
}
441+
}
442+
416443
PARSE_OPTIONS_GOTO_TRACE(cmdline, options);
417444
}
418445

src/goto-checker/bmc_util.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,9 @@ void slice(
8787
"(unwind):" \
8888
"(unwindset):" \
8989
"(graphml-witness):" \
90-
"(unwindset):"
90+
"(unwindset):" \
91+
"(memory-snapshot):" \
92+
"(initial-location):"
9193

9294
#define HELP_BMC \
9395
" --paths [strategy] explore paths one at a time\n" \
@@ -106,7 +108,13 @@ void slice(
106108
" --no-self-loops-to-assumptions\n" \
107109
" do not simplify while(1){} to assume(0)\n" \
108110
" --no-pretty-names do not simplify identifiers\n" \
109-
" --graphml-witness filename write the witness in GraphML format to filename\n" // NOLINT(*)
111+
" --graphml-witness filename write the witness in GraphML format to " \
112+
"filename\n" \
113+
" --memory-snapshot <file> initialize memory from given JSON memory " \
114+
"snapshot\n" \
115+
" --initial-location <func[:<n>]\n" \
116+
" start symex from given function and " \
117+
"location\n number (use with --memory-snapshot)\n"
110118
// clang-format on
111119

112120
#endif // CPROVER_GOTO_CHECKER_BMC_UTIL_H

src/goto-symex/goto_symex.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,22 @@ class goto_symext
118118
const get_goto_functiont &get_goto_function,
119119
symbol_tablet &new_symbol_table);
120120

121+
/// Symex program starting from given instruction and initialize the memory
122+
/// with the given snapshot
123+
///
124+
/// \param get_goto_function mapping from function ids to goto functions
125+
/// \param new_symbol_table symbol table to which to add symbols generated
126+
/// during symex
127+
/// \param snapshot memory snapshot represented as a symbol table, the `value`
128+
/// field of each symbol holds the value to initialize the corresponding
129+
/// symbol expression with
130+
/// \param it iterator to goto instruction to start symex from
131+
virtual void symex_from_instruction_with_snapshot(
132+
const get_goto_functiont &get_goto_function,
133+
symbol_tablet &new_symbol_table,
134+
const symbol_tablet &snapshot,
135+
goto_programt::const_targett it);
136+
121137
/// Performs symbolic execution using a state and equation that have
122138
/// already been used to symex part of the program. The state is not
123139
/// re-initialized; instead, symbolic execution resumes from the program

src/goto-symex/symex_main.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ Author: Daniel Kroening, [email protected]
2323

2424
#include <analyses/dirty.h>
2525

26+
#include <iostream>
27+
2628
symex_configt::symex_configt(const optionst &options)
2729
: max_depth(options.get_unsigned_int_option("depth")),
2830
doing_path_exploration(options.is_set("paths")),
@@ -321,6 +323,47 @@ void goto_symext::symex_from_entry_point_of(
321323
state, get_goto_function, new_symbol_table);
322324
}
323325

326+
void goto_symext::symex_from_instruction_with_snapshot(
327+
const get_goto_functiont &get_goto_function,
328+
symbol_tablet &new_symbol_table,
329+
const symbol_tablet &snapshot,
330+
goto_programt::const_targett pc)
331+
{
332+
statet state;
333+
334+
// First initialize state from snapshot
335+
336+
state.symex_target = &target;
337+
state.source.pc = pc;
338+
339+
for(const auto &pair : snapshot)
340+
{
341+
const symbolt &symbol = pair.second;
342+
343+
if(!symbol.is_static_lifetime)
344+
continue;
345+
346+
symex_assign(state, code_assignt(symbol.symbol_expr(), symbol.value));
347+
}
348+
349+
// Now do actual program
350+
351+
const irep_idt id = goto_programt::get_function_id(pc);
352+
const goto_functionst::goto_functiont &goto_function = get_goto_function(id);
353+
354+
INVARIANT(
355+
goto_function.body_available(), "starting function should have a body");
356+
357+
initialize_entry_point(
358+
state,
359+
get_goto_function,
360+
id,
361+
pc,
362+
prev(goto_function.body.instructions.end()));
363+
364+
symex_with_state(state, get_goto_function, new_symbol_table);
365+
}
366+
324367
/// do just one step
325368
void goto_symext::symex_step(
326369
const get_goto_functiont &get_goto_function,

0 commit comments

Comments
 (0)