Skip to content

Commit 0965290

Browse files
Fix path explorer unit test
1 parent f4adde7 commit 0965290

File tree

2 files changed

+128
-84
lines changed

2 files changed

+128
-84
lines changed

unit/path_strategies.cpp

Lines changed: 125 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,11 @@ Author: Kareem Khazem <[email protected]>, 2018
1616

1717
#include <ansi-c/ansi_c_language.h>
1818

19-
#include <cbmc/bmc.h>
2019
#include <cbmc/cbmc_parse_options.h>
2120

22-
#include <goto-checker/solver_factory.h>
21+
#include <goto-checker/bmc_util.h>
22+
#include <goto-checker/goto_symex_property_decider.h>
23+
#include <goto-checker/symex_bmc.h>
2324

2425
#include <langapi/mode.h>
2526

@@ -42,8 +43,8 @@ Author: Kareem Khazem <[email protected]>, 2018
4243
// `goto` instruction.
4344
//
4445
// Whenever symbolic execution reaches the end of a path, you should expect a
45-
// result. Results are either SUCCESS, meaning that verification of that path
46-
// succeeded, or FAILURE, meaning that there was an assertion failure on that
46+
// result. Results are either DONE, meaning that verification of that path
47+
// succeeded, or FOUND_FAIL, meaning that there was an assertion failure on that
4748
// path.
4849
//
4950
// To figure out what the events should be, run CBMC on the test program with
@@ -80,14 +81,18 @@ SCENARIO("path strategies")
8081
"lifo",
8182
opts_callback,
8283
c,
83-
{symex_eventt::resume(symex_eventt::enumt::JUMP, 7),
84+
{// Entry state is line 0
85+
symex_eventt::resume(symex_eventt::enumt::NEXT, 0),
86+
symex_eventt::resume(symex_eventt::enumt::JUMP, 7),
8487
symex_eventt::resume(symex_eventt::enumt::NEXT, 5),
8588
symex_eventt::result(symex_eventt::enumt::SUCCESS)});
8689
check_with_strategy(
8790
"fifo",
8891
opts_callback,
8992
c,
90-
{symex_eventt::resume(symex_eventt::enumt::NEXT, 5),
93+
{// Entry state is line 0
94+
symex_eventt::resume(symex_eventt::enumt::NEXT, 0),
95+
symex_eventt::resume(symex_eventt::enumt::NEXT, 5),
9196
symex_eventt::resume(symex_eventt::enumt::JUMP, 7),
9297
symex_eventt::result(symex_eventt::enumt::SUCCESS)});
9398
}
@@ -120,7 +125,9 @@ SCENARIO("path strategies")
120125
"lifo",
121126
opts_callback,
122127
c,
123-
{// Outer else, inner else
128+
{// Entry state is line 0
129+
symex_eventt::resume(symex_eventt::enumt::NEXT, 0),
130+
// Outer else, inner else
124131
symex_eventt::resume(symex_eventt::enumt::JUMP, 13),
125132
symex_eventt::resume(symex_eventt::enumt::JUMP, 16),
126133
// Outer else, inner if
@@ -136,7 +143,9 @@ SCENARIO("path strategies")
136143
"fifo",
137144
opts_callback,
138145
c,
139-
{// Expand outer if, but don't continue depth-first
146+
{// Entry state is line 0
147+
symex_eventt::resume(symex_eventt::enumt::NEXT, 0),
148+
// Expand outer if, but don't continue depth-first
140149
symex_eventt::resume(symex_eventt::enumt::NEXT, 6),
141150
// Jump to outer else, but again don't continue depth-first
142151
symex_eventt::resume(symex_eventt::enumt::JUMP, 13),
@@ -175,6 +184,8 @@ SCENARIO("path strategies")
175184
opts_callback,
176185
c,
177186
{
187+
// Entry state is line 0
188+
symex_eventt::resume(symex_eventt::enumt::NEXT, 0),
178189
// The path where we skip the loop body. Successful because the path is
179190
// implausible, we cannot have skipped the body if x == 1.
180191
symex_eventt::resume(symex_eventt::enumt::JUMP, 9),
@@ -200,6 +211,8 @@ SCENARIO("path strategies")
200211
opts_callback,
201212
c,
202213
{
214+
// Entry state is line 0
215+
symex_eventt::resume(symex_eventt::enumt::NEXT, 0),
203216
// The path where we skip the loop body. Successful because the path is
204217
// implausible, we cannot have skipped the body if x == 1.
205218
//
@@ -247,7 +260,9 @@ SCENARIO("path strategies")
247260
"lifo",
248261
no_halt_callback,
249262
c,
250-
{symex_eventt::resume(symex_eventt::enumt::JUMP, 7),
263+
{// Entry state is line 0
264+
symex_eventt::resume(symex_eventt::enumt::NEXT, 0),
265+
symex_eventt::resume(symex_eventt::enumt::JUMP, 7),
251266
symex_eventt::result(symex_eventt::enumt::FAILURE),
252267
symex_eventt::resume(symex_eventt::enumt::NEXT, 5),
253268
symex_eventt::result(symex_eventt::enumt::FAILURE),
@@ -260,7 +275,9 @@ SCENARIO("path strategies")
260275
"lifo",
261276
halt_callback,
262277
c,
263-
{symex_eventt::resume(symex_eventt::enumt::JUMP, 7),
278+
{// Entry state is line 0
279+
symex_eventt::resume(symex_eventt::enumt::NEXT, 0),
280+
symex_eventt::resume(symex_eventt::enumt::JUMP, 7),
264281
symex_eventt::result(symex_eventt::enumt::FAILURE),
265282
// Overall result
266283
symex_eventt::result(symex_eventt::enumt::FAILURE)});
@@ -273,24 +290,24 @@ SCENARIO("path strategies")
273290

274291
void symex_eventt::validate_result(
275292
listt &events,
276-
const safety_checkert::resultt result,
293+
const incremental_goto_checkert::resultt::progresst result,
277294
std::size_t &counter)
278295
{
279296
INFO(
280297
"Expecting result to be '"
281-
<< (result == safety_checkert::resultt::SAFE ? "success" : "failure")
298+
<< (result == incremental_goto_checkert::resultt::progresst::DONE
299+
? "success"
300+
: "failure")
282301
<< "' (item at index [" << counter << "] in expected results list");
283302
++counter;
284303

285-
REQUIRE(result != safety_checkert::resultt::ERROR);
286-
287-
if(result == safety_checkert::resultt::SAFE)
304+
if(result == incremental_goto_checkert::resultt::progresst::DONE)
288305
{
289306
REQUIRE(!events.empty());
290307
REQUIRE(events.front().first == symex_eventt::enumt::SUCCESS);
291308
events.pop_front();
292309
}
293-
else if(result == safety_checkert::resultt::UNSAFE)
310+
else
294311
{
295312
REQUIRE(!events.empty());
296313
REQUIRE(events.front().first == symex_eventt::enumt::FAILURE);
@@ -305,7 +322,9 @@ void symex_eventt::validate_resume(
305322
{
306323
REQUIRE(!events.empty());
307324

308-
int dst = std::stoi(state.saved_target->source_location.get_line().c_str());
325+
int dst = 0;
326+
if(!state.saved_target->source_location.get_line().empty())
327+
dst = std::stoi(state.saved_target->source_location.get_line().c_str());
309328

310329
if(state.has_saved_jump_target)
311330
{
@@ -332,11 +351,8 @@ void symex_eventt::validate_resume(
332351
events.pop_front();
333352
}
334353

335-
// This is a simplified version of bmct::do_language_agnostic_bmc, without all
336-
// the edge cases to deal with java programs, bytecode loaded on demand, etc. We
337-
// need to replicate some of this stuff because the worklist is a local variable
338-
// of do_language_agnostic_bmc, and we need to check the worklist every time
339-
// symex returns.
354+
// This is a simplified copy of single_path_symex_checkert
355+
// because we have to check the worklist every time goto-symex returns.
340356
void _check_with_strategy(
341357
const std::string &strategy,
342358
const std::string &program,
@@ -356,95 +372,122 @@ void _check_with_strategy(
356372
config.main = "main";
357373
config.set(cmdline);
358374

359-
optionst opts;
360-
cbmc_parse_optionst::set_default_options(opts);
361-
opts.set_option("paths", true);
362-
opts.set_option("exploration-strategy", strategy);
363-
364-
opts_callback(opts);
365-
366-
ui_message_handlert mh(cmdline, "path-explore");
367-
mh.set_verbosity(0);
368-
messaget log(mh);
369-
375+
optionst options;
376+
cbmc_parse_optionst::set_default_options(options);
377+
options.set_option("paths", true);
378+
options.set_option("exploration-strategy", strategy);
370379
REQUIRE(is_valid_path_strategy(strategy));
371-
std::unique_ptr<path_storaget> worklist = get_path_strategy(strategy);
372-
guard_managert guard_manager;
380+
opts_callback(options);
381+
382+
ui_message_handlert ui_message_handler(cmdline, "path-explore");
383+
ui_message_handler.set_verbosity(0);
384+
messaget log(ui_message_handler);
373385

374-
goto_modelt gm;
386+
goto_modelt goto_model;
375387
int ret;
376-
ret = cbmc_parse_optionst::get_goto_program(gm, opts, cmdline, log, mh);
388+
ret = cbmc_parse_optionst::get_goto_program(
389+
goto_model, options, cmdline, log, ui_message_handler);
377390
REQUIRE(ret == -1);
378391

379-
namespacet ns(gm.get_symbol_table());
380-
solver_factoryt solver_factory(opts, ns, mh, false);
381-
std::unique_ptr<solver_factoryt::solvert> cbmc_solver =
382-
solver_factory.get_solver();
383-
prop_convt &initial_pc = cbmc_solver->prop_conv();
384-
std::function<bool(void)> callback = []() { return false; };
385-
386-
safety_checkert::resultt overall_result = safety_checkert::resultt::SAFE;
387-
std::size_t expected_results_cnt = 0;
392+
symbol_tablet symex_symbol_table;
393+
namespacet ns(goto_model.get_symbol_table(), symex_symbol_table);
394+
propertiest properties(initialize_properties(goto_model));
395+
std::unique_ptr<path_storaget> worklist = get_path_strategy(strategy);
396+
guard_managert guard_manager;
388397

389-
bmct bmc(
390-
opts,
391-
gm.get_symbol_table(),
392-
mh,
393-
initial_pc,
394-
*worklist,
395-
callback,
396-
guard_manager);
397-
safety_checkert::resultt tmp_result = bmc.run(gm);
398-
399-
if(tmp_result != safety_checkert::resultt::PAUSED)
400398
{
401-
symex_eventt::validate_result(events, tmp_result, expected_results_cnt);
402-
overall_result &= tmp_result;
403-
}
399+
// Put initial state into the work list
400+
symex_target_equationt equation(ui_message_handler);
401+
symex_bmct symex(
402+
ui_message_handler,
403+
goto_model.get_symbol_table(),
404+
equation,
405+
options,
406+
*worklist,
407+
guard_manager);
408+
setup_symex(symex, ns, options, ui_message_handler);
404409

405-
if(
406-
overall_result == safety_checkert::resultt::UNSAFE &&
407-
opts.get_bool_option("stop-on-fail") && opts.is_set("paths"))
408-
{
409-
worklist->clear();
410+
symex.initialize_path_storage_from_entry_point_of(
411+
goto_symext::get_goto_function(goto_model), symex_symbol_table);
410412
}
411413

414+
std::size_t expected_results_cnt = 0;
412415
while(!worklist->empty())
413416
{
414-
cbmc_solver = solver_factory.get_solver();
415-
prop_convt &pc = cbmc_solver->prop_conv();
416417
path_storaget::patht &resume = worklist->peek();
417418

418419
symex_eventt::validate_resume(events, resume.state, expected_results_cnt);
419420

420-
path_explorert pe(
421-
opts,
422-
gm.get_symbol_table(),
423-
mh,
424-
pc,
421+
symex_bmct symex(
422+
ui_message_handler,
423+
goto_model.get_symbol_table(),
425424
resume.equation,
426-
resume.state,
425+
options,
427426
*worklist,
428-
guard_manager,
429-
callback);
430-
tmp_result = pe.run(gm);
427+
guard_manager);
428+
setup_symex(symex, ns, options, ui_message_handler);
429+
430+
symex.resume_symex_from_saved_state(
431+
goto_symext::get_goto_function(goto_model),
432+
resume.state,
433+
&resume.equation,
434+
symex_symbol_table);
435+
postprocess_equation(
436+
symex, resume.equation, options, ns, ui_message_handler);
437+
438+
incremental_goto_checkert::resultt result(
439+
incremental_goto_checkert::resultt::progresst::DONE);
431440

432-
if(tmp_result != safety_checkert::resultt::PAUSED)
441+
if(symex.get_remaining_vccs() > 0)
433442
{
434-
symex_eventt::validate_result(events, tmp_result, expected_results_cnt);
435-
overall_result &= tmp_result;
443+
update_properties_status_from_symex_target_equation(
444+
properties, result.updated_properties, resume.equation);
445+
446+
goto_symex_property_decidert property_decider(
447+
options, ui_message_handler, resume.equation, ns);
448+
449+
const auto solver_runtime = prepare_property_decider(
450+
properties, resume.equation, property_decider, ui_message_handler);
451+
452+
run_property_decider(
453+
result,
454+
properties,
455+
property_decider,
456+
ui_message_handler,
457+
solver_runtime,
458+
false);
459+
460+
symex_eventt::validate_result(
461+
events, result.progress, expected_results_cnt);
436462
}
463+
437464
worklist->pop();
438465

439466
if(
440-
overall_result == safety_checkert::resultt::UNSAFE &&
441-
opts.get_bool_option("stop-on-fail"))
467+
result.progress ==
468+
incremental_goto_checkert::resultt::progresst::FOUND_FAIL &&
469+
options.get_bool_option("stop-on-fail"))
442470
{
443471
worklist->clear();
444472
}
473+
474+
if(worklist->empty())
475+
{
476+
update_status_of_not_checked_properties(
477+
properties, result.updated_properties);
478+
479+
update_status_of_unknown_properties(
480+
properties, result.updated_properties);
481+
}
445482
}
446483

447-
symex_eventt::validate_result(events, overall_result, expected_results_cnt);
484+
const resultt overall_result = determine_result(properties);
485+
symex_eventt::validate_result(
486+
events,
487+
overall_result == resultt::FAIL
488+
? incremental_goto_checkert::resultt::progresst::FOUND_FAIL
489+
: incremental_goto_checkert::resultt::progresst::DONE,
490+
expected_results_cnt);
448491

449492
INFO("The expected results list contains " << events.size() << " items");
450493
REQUIRE(events.empty());

unit/path_strategies.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
#define CPROVER_PATH_STRATEGIES_H
77

88
#include <goto-programs/goto_model.h>
9-
#include <goto-programs/safety_checker.h>
9+
10+
#include <goto-checker/incremental_goto_checker.h>
1011

1112
#include <goto-symex/goto_symex_state.h>
1213

@@ -38,7 +39,7 @@ struct symex_eventt
3839

3940
static void validate_result(
4041
listt &events,
41-
const safety_checkert::resultt result,
42+
const incremental_goto_checkert::resultt::progresst result,
4243
std::size_t &);
4344

4445
static void

0 commit comments

Comments
 (0)