Skip to content

Commit ad416e2

Browse files
committed
Add harness generator to initialise memory from a memory snapshot
This adds a harness generator to goto-harness that takes a goto program and a memory snapshot in JSON format (via the option --memory-snapshot), and then builds a harness that initialises the global variables from the snapshot. In addition the harness generator provides the option --initial-location to specify the starting point of the execution. The harness thus behaves as if the original program would start execution at the given program location.
1 parent 8f0a78d commit ad416e2

7 files changed

+406
-2
lines changed

src/goto-harness/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,6 @@ generic_includes(goto-harness)
55
target_link_libraries(goto-harness
66
util
77
goto-programs
8+
json
9+
json-symtab-language
810
)

src/goto-harness/Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ SRC = \
44
goto_harness_generator_factory.cpp \
55
goto_harness_main.cpp \
66
goto_harness_parse_options.cpp \
7+
memory_snapshot_harness_generator.cpp \
78
# Empty last line
89

910
OBJ += \
@@ -12,6 +13,8 @@ OBJ += \
1213
../big-int/big-int$(LIBEXT) \
1314
../langapi/langapi$(LIBEXT) \
1415
../linking/linking$(LIBEXT) \
16+
../json/json$(LIBEXT) \
17+
../json-symtab-language/json-symtab-language$(LIBEXT) \
1518
# Empty last line
1619

1720
INCLUDES= -I ..

src/goto-harness/goto_harness_parse_options.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ Author: Diffblue Ltd.
2525

2626
#include "function_call_harness_generator.h"
2727
#include "goto_harness_generator_factory.h"
28+
#include "memory_snapshot_harness_generator.h"
2829

2930
// The basic idea is that this module is handling the following
3031
// sequence of events:
@@ -103,7 +104,8 @@ void goto_harness_parse_optionst::help()
103104
"generate\n"
104105
<< "--harness-type one of the harness types listed below\n"
105106
<< "\n\n"
106-
<< FUNCTION_HARNESS_GENERATOR_HELP << messaget::eom;
107+
<< FUNCTION_HARNESS_GENERATOR_HELP << "\n\n"
108+
<< MEMORY_SNAPSHOT_HARNESS_GENERATOR_HELP << messaget::eom;
107109
}
108110

109111
goto_harness_parse_optionst::goto_harness_parse_optionst(
@@ -162,6 +164,12 @@ goto_harness_generator_factoryt goto_harness_parse_optionst::make_factory()
162164
return util_make_unique<function_call_harness_generatort>(
163165
ui_message_handler);
164166
});
167+
168+
factory.register_generator("initialise-with-memory-snapshot", [this]() {
169+
return util_make_unique<memory_snapshot_harness_generatort>(
170+
ui_message_handler);
171+
});
172+
165173
return factory;
166174
}
167175

src/goto-harness/goto_harness_parse_options.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ Author: Diffblue Ltd.
2323
"(version)" \
2424
GOTO_HARNESS_FACTORY_OPTIONS \
2525
FUNCTION_HARNESS_GENERATOR_OPTIONS \
26+
MEMORY_SNAPSHOT_HARNESS_GENERATOR_OPTIONS \
2627
// end GOTO_HARNESS_OPTIONS
2728

2829
// clang-format on
Lines changed: 306 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,306 @@
1+
/******************************************************************\
2+
3+
Module: Harness to initialise memory from memory snapshot
4+
5+
Author: Daniel Poetzl
6+
7+
\******************************************************************/
8+
9+
#include "memory_snapshot_harness_generator.h"
10+
11+
#include <goto-programs/goto_convert.h>
12+
13+
#include <json/json_parser.h>
14+
15+
#include <json-symtab-language/json_symbol_table.h>
16+
17+
#include <util/exception_utils.h>
18+
#include <util/fresh_symbol.h>
19+
#include <util/message.h>
20+
#include <util/string2int.h>
21+
#include <util/string_utils.h>
22+
#include <util/symbol_table.h>
23+
24+
#include "goto_harness_generator_factory.h"
25+
26+
void memory_snapshot_harness_generatort::handle_option(
27+
const std::string &option,
28+
const std::list<std::string> &values)
29+
{
30+
if(option == "memory-snapshot")
31+
{
32+
memory_snapshot = require_exactly_one_value(option, values);
33+
}
34+
else if(option == "initial-location")
35+
{
36+
const std::string initial_location =
37+
require_exactly_one_value(option, values);
38+
39+
std::vector<std::string> start;
40+
split_string(initial_location, ':', start, true);
41+
42+
if(
43+
start.size() == 0 || (start.size() >= 1 && start.front().empty()) ||
44+
(start.size() == 2 && start.back().empty()) || start.size() > 2)
45+
{
46+
throw invalid_command_line_argument_exceptiont(
47+
"invalid initial location specification", "--initial-location");
48+
}
49+
50+
function = start.front();
51+
52+
if(start.size() == 2)
53+
{
54+
location_number = optionalt<unsigned>(safe_string2unsigned(start.back()));
55+
}
56+
}
57+
else
58+
{
59+
throw invalid_command_line_argument_exceptiont(
60+
"unrecognized option for memory snapshot harness generator",
61+
"--" + option);
62+
}
63+
}
64+
65+
void memory_snapshot_harness_generatort::validate_options()
66+
{
67+
if(memory_snapshot.empty())
68+
{
69+
throw invalid_command_line_argument_exceptiont(
70+
"option --memory_snapshot is required",
71+
"--harness-type initialise-from-memory-snapshot");
72+
}
73+
74+
if(function.empty())
75+
{
76+
INVARIANT(
77+
location_number.has_value(),
78+
"when `function` is empty then the option --initial-location was not "
79+
"given and thus `location_number` was not set");
80+
81+
throw invalid_command_line_argument_exceptiont(
82+
"option --initial-location is required",
83+
"--harness-type initialise-from-memory-snapshot");
84+
}
85+
}
86+
87+
void memory_snapshot_harness_generatort::add_init_section(
88+
goto_modelt &goto_model) const
89+
{
90+
goto_functionst &goto_functions = goto_model.goto_functions;
91+
symbol_tablet &symbol_table = goto_model.symbol_table;
92+
93+
goto_functiont &goto_function = goto_functions.function_map[function];
94+
const symbolt &function_symbol = symbol_table.lookup_ref(function);
95+
96+
goto_programt &goto_program = goto_function.body;
97+
98+
const symbolt &symbol = get_fresh_aux_symbol(
99+
bool_typet(),
100+
id2string(function),
101+
"func_init_done",
102+
source_locationt(),
103+
function_symbol.mode,
104+
symbol_table);
105+
106+
const symbol_exprt &var = symbol.symbol_expr();
107+
108+
// initialise var in __CPROVER_initialize if it is present
109+
const auto f_it =
110+
goto_functions.function_map.find(CPROVER_PREFIX "initialize");
111+
112+
if(f_it != goto_functions.function_map.end())
113+
{
114+
goto_programt &goto_program = f_it->second.body;
115+
116+
auto init_it =
117+
goto_program.insert_before(std::prev(goto_program.instructions.end()));
118+
119+
init_it->make_assignment(code_assignt(var, false_exprt()));
120+
}
121+
122+
const goto_programt::const_targett start_it =
123+
goto_program.instructions.begin();
124+
125+
goto_programt::const_targett it;
126+
127+
if(location_number.has_value())
128+
{
129+
const auto opt_it = goto_program.get_target(*location_number);
130+
131+
if(!opt_it.has_value())
132+
{
133+
throw invalid_command_line_argument_exceptiont(
134+
"no instruction with location number " +
135+
std::to_string(*location_number) + " in function " +
136+
as_string(function),
137+
"--initial-location");
138+
}
139+
140+
it = *opt_it;
141+
}
142+
else
143+
{
144+
it = start_it;
145+
}
146+
147+
auto ins_it1 = goto_program.insert_before(start_it);
148+
ins_it1->make_goto(goto_program.const_cast_target(start_it));
149+
ins_it1->guard = var;
150+
151+
auto ins_it2 = goto_program.insert_after(ins_it1);
152+
ins_it2->make_assignment(code_assignt(var, true_exprt()));
153+
154+
auto ins_it3 = goto_program.insert_after(ins_it2);
155+
ins_it3->make_goto(goto_program.const_cast_target(it));
156+
}
157+
158+
void memory_snapshot_harness_generatort::add_assignments_to_globals(
159+
const symbol_tablet &snapshot,
160+
code_blockt &code) const
161+
{
162+
for(const auto &pair : snapshot)
163+
{
164+
const symbolt &symbol = pair.second;
165+
166+
if(!symbol.is_static_lifetime)
167+
continue;
168+
169+
code_assignt code_assign(symbol.symbol_expr(), symbol.value);
170+
171+
code.add(code_assign);
172+
}
173+
}
174+
175+
void memory_snapshot_harness_generatort::add_call_with_nondet_arguments(
176+
const symbolt &called_function_symbol,
177+
code_blockt &code) const
178+
{
179+
const code_typet &code_type = to_code_type(called_function_symbol.type);
180+
181+
code_function_callt::argumentst arguments;
182+
183+
for(const code_typet::parametert &parameter : code_type.parameters())
184+
{
185+
arguments.push_back(side_effect_expr_nondett(parameter.type()));
186+
}
187+
188+
code_function_callt function_call(
189+
called_function_symbol.symbol_expr(), arguments);
190+
code.add(function_call);
191+
}
192+
193+
void memory_snapshot_harness_generatort::insert_function(
194+
goto_modelt &goto_model,
195+
const symbolt &function) const
196+
{
197+
const auto r = goto_model.symbol_table.insert(function);
198+
CHECK_RETURN(r.second);
199+
200+
auto f_it = goto_model.goto_functions.function_map.insert(
201+
std::make_pair(function.name, goto_functiont()));
202+
CHECK_RETURN(f_it.second);
203+
204+
goto_functiont &harness_function = f_it.first->second;
205+
harness_function.type = to_code_type(function.type);
206+
207+
goto_convert(
208+
to_code_block(to_code(function.value)),
209+
goto_model.symbol_table,
210+
harness_function.body,
211+
message_handler,
212+
function.mode);
213+
214+
harness_function.body.add(goto_programt::make_end_function());
215+
}
216+
217+
void memory_snapshot_harness_generatort::get_memory_snapshot(
218+
const std::string &file,
219+
symbol_tablet &snapshot) const
220+
{
221+
jsont json;
222+
223+
const bool r = parse_json(memory_snapshot, message_handler, json);
224+
225+
if(r)
226+
{
227+
throw deserialization_exceptiont("failed to read JSON memory snapshot");
228+
}
229+
230+
// throws a deserialization_exceptiont or an incorrect_goto_program_exceptiont
231+
// on failure to read JSON symbol table
232+
symbol_table_from_json(json, snapshot);
233+
}
234+
235+
void memory_snapshot_harness_generatort::generate(
236+
goto_modelt &goto_model,
237+
const irep_idt &harness_function_name)
238+
{
239+
symbol_tablet snapshot;
240+
get_memory_snapshot(memory_snapshot, snapshot);
241+
242+
symbol_tablet &symbol_table = goto_model.symbol_table;
243+
goto_functionst &goto_functions = goto_model.goto_functions;
244+
245+
const symbolt *called_function_symbol = symbol_table.lookup(function);
246+
247+
if(called_function_symbol == nullptr)
248+
{
249+
throw invalid_command_line_argument_exceptiont(
250+
"function `" + id2string(function) + "` not found in the symbol table",
251+
"--initial-location");
252+
}
253+
254+
{
255+
const auto f_it = goto_functions.function_map.find(function);
256+
257+
if(f_it == goto_functions.function_map.end())
258+
{
259+
throw invalid_command_line_argument_exceptiont(
260+
"goto function `" + id2string(function) + "` not found",
261+
"--initial-location");
262+
}
263+
264+
if(!f_it->second.body_available())
265+
{
266+
throw invalid_command_line_argument_exceptiont(
267+
"given function `" + id2string(function) + "` does not have a body",
268+
"--initial-location");
269+
}
270+
}
271+
272+
add_init_section(goto_model);
273+
274+
if(symbol_table.has_symbol(harness_function_name))
275+
{
276+
throw invalid_command_line_argument_exceptiont(
277+
"harness function `" + id2string(harness_function_name) +
278+
"` already in "
279+
"the symbol table",
280+
"--" GOTO_HARNESS_GENERATOR_HARNESS_FUNCTION_NAME_OPT);
281+
}
282+
283+
code_blockt harness_function_body;
284+
285+
add_assignments_to_globals(snapshot, harness_function_body);
286+
287+
add_call_with_nondet_arguments(
288+
*called_function_symbol, harness_function_body);
289+
290+
// Create harness function symbol
291+
292+
symbolt harness_function_symbol;
293+
harness_function_symbol.name = harness_function_name;
294+
harness_function_symbol.base_name = harness_function_name;
295+
harness_function_symbol.pretty_name = harness_function_name;
296+
297+
harness_function_symbol.is_lvalue = true;
298+
harness_function_symbol.mode = called_function_symbol->mode;
299+
harness_function_symbol.type = code_typet({}, empty_typet());
300+
harness_function_symbol.value = harness_function_body;
301+
302+
// Add harness function to goto model and symbol table
303+
insert_function(goto_model, harness_function_symbol);
304+
305+
goto_functions.update();
306+
}

0 commit comments

Comments
 (0)