Skip to content

Commit 6cafb75

Browse files
karkhazPetr Bauch
authored and
Petr Bauch
committed
Only safety-check paths when new VCCs get added
CBMC will no longer bother running safety checks on path segments that did not generate any new VCCs when running in path-exploration mode. A "path segment" is a list of instructions between two program branch points. CBMC would previously pause symbolic execution and run safety checks at every branch point, which is wasteful when no additional VCCs have been generated since the last pause. As of this commit, CBMC will check to see if new VCCs have been added, and only do the safety check if so. To support this, the new member goto_symext::path_segment_vccs records the number of VCCs that were newly generated along this path segment. It differs from the VCC counters in goto_symex_statet, which hold the number of VCCs generated along the current path since the start of the program. goto_symext objects are minted for each path segment, so they don't hold any information about the VCCs previously along the path. This commit also removes the "Starting new path" output, since this no longer makes much sense. On the other hand, there is an additional final status output; CBMC will report failure after the entire program has been explored if even a single path contained a failing assertion, and report success otherwise. The unit tests have been updated to reflect the fact that CBMC no longer emits "SUCCESS" at each branch point and at the end of paths, and also that CBMC makes one final report of the program safety as a whole. This commit fixes diffblue#2684.
1 parent 2ea50f7 commit 6cafb75

File tree

5 files changed

+68
-41
lines changed

5 files changed

+68
-41
lines changed

src/cbmc/bmc.cpp

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -270,9 +270,6 @@ safety_checkert::resultt bmct::execute(
270270
const goto_functionst &goto_functions =
271271
goto_model.get_goto_functions();
272272

273-
if(symex.should_pause_symex)
274-
return safety_checkert::resultt::PAUSED;
275-
276273
// This provides the driver program the opportunity to do things like a
277274
// symbol-table or goto-functions dump instead of actually running the
278275
// checker, like show-vcc except driver-program specific.
@@ -282,9 +279,14 @@ safety_checkert::resultt bmct::execute(
282279
if(driver_callback_after_symex && driver_callback_after_symex())
283280
return safety_checkert::resultt::SAFE; // to indicate non-error
284281

285-
// add a partial ordering, if required
286282
if(equation.has_threads())
287283
{
284+
// When doing path exploration in a concurrent setting, we should avoid
285+
// model-checking the program until we reach the end of a path.
286+
if(symex.should_pause_symex)
287+
return safety_checkert::resultt::PAUSED;
288+
289+
// add a partial ordering, if required
288290
memory_model->set_message_handler(get_message_handler());
289291
(*memory_model)(equation);
290292
}
@@ -328,6 +330,8 @@ safety_checkert::resultt bmct::execute(
328330
!options.get_bool_option("program-only") &&
329331
symex.get_remaining_vccs() == 0)
330332
{
333+
if(options.is_set("paths"))
334+
return safety_checkert::resultt::PAUSED;
331335
report_success();
332336
output_graphml(resultt::SAFE);
333337
return safety_checkert::resultt::SAFE;
@@ -339,7 +343,10 @@ safety_checkert::resultt bmct::execute(
339343
return safety_checkert::resultt::SAFE;
340344
}
341345

342-
return decide(goto_functions, prop_conv);
346+
if(!options.is_set("paths") || symex.path_segment_vccs > 0)
347+
return decide(goto_functions, prop_conv);
348+
349+
return safety_checkert::resultt::PAUSED;
343350
}
344351

345352
catch(const std::string &error_str)
@@ -406,6 +413,10 @@ void bmct::slice()
406413
statistics() << "Generated " << symex.get_total_vccs() << " VCC(s), "
407414
<< symex.get_remaining_vccs()
408415
<< " remaining after simplification" << eom;
416+
417+
if(options.is_set("paths"))
418+
statistics() << "Generated " << symex.path_segment_vccs
419+
<< " new VCC(s) along current path segment" << eom;
409420
}
410421

411422
safety_checkert::resultt bmct::run(
@@ -494,8 +505,8 @@ int bmct::do_language_agnostic_bmc(
494505
std::function<void(bmct &, const symbol_tablet &)> driver_configure_bmc,
495506
std::function<bool(void)> callback_after_symex)
496507
{
497-
safety_checkert::resultt final_result = safety_checkert::resultt::UNKNOWN;
498-
safety_checkert::resultt tmp_result = safety_checkert::resultt::UNKNOWN;
508+
safety_checkert::resultt final_result = safety_checkert::resultt::SAFE;
509+
safety_checkert::resultt tmp_result = safety_checkert::resultt::SAFE;
499510
const symbol_tablet &symbol_table = model.get_symbol_table();
500511
messaget message(ui);
501512
std::unique_ptr<path_storaget> worklist;
@@ -554,11 +565,6 @@ int bmct::do_language_agnostic_bmc(
554565

555566
while(!worklist->empty())
556567
{
557-
if(tmp_result != safety_checkert::resultt::PAUSED)
558-
message.status() << "___________________________\n"
559-
<< "Starting new path (" << worklist->size()
560-
<< " to go)\n"
561-
<< message.eom;
562568
cbmc_solverst solvers(
563569
opts,
564570
symbol_table,
@@ -613,13 +619,15 @@ int bmct::do_language_agnostic_bmc(
613619
switch(final_result)
614620
{
615621
case safety_checkert::resultt::SAFE:
622+
if(opts.is_set("paths"))
623+
report_success(message, ui);
616624
return CPROVER_EXIT_VERIFICATION_SAFE;
617625
case safety_checkert::resultt::UNSAFE:
626+
if(opts.is_set("paths"))
627+
report_failure(message, ui);
618628
return CPROVER_EXIT_VERIFICATION_UNSAFE;
619629
case safety_checkert::resultt::ERROR:
620630
return CPROVER_EXIT_INTERNAL_ERROR;
621-
case safety_checkert::resultt::UNKNOWN:
622-
return CPROVER_EXIT_INTERNAL_ERROR;
623631
case safety_checkert::resultt::PAUSED:
624632
UNREACHABLE;
625633
}

src/goto-programs/safety_checker.h

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,6 @@ class safety_checkert:public messaget
4242
/// doing path exploration; the symex state has been saved, and symex should
4343
/// be resumed by the caller.
4444
PAUSED,
45-
/// We haven't yet assigned a safety check result to this object. A value of
46-
/// UNKNOWN can be used to initialize a resultt object, and that object may
47-
/// then safely be used with the |= and &= operators.
48-
UNKNOWN
4945
};
5046

5147
// check whether all assertions in goto_functions are safe
@@ -76,9 +72,6 @@ operator&=(safety_checkert::resultt &a, safety_checkert::resultt const &b)
7672
b != safety_checkert::resultt::PAUSED);
7773
switch(a)
7874
{
79-
case safety_checkert::resultt::UNKNOWN:
80-
a = b;
81-
return a;
8275
case safety_checkert::resultt::ERROR:
8376
return a;
8477
case safety_checkert::resultt::SAFE:
@@ -107,9 +100,6 @@ operator|=(safety_checkert::resultt &a, safety_checkert::resultt const &b)
107100
b != safety_checkert::resultt::PAUSED);
108101
switch(a)
109102
{
110-
case safety_checkert::resultt::UNKNOWN:
111-
a = b;
112-
return a;
113103
case safety_checkert::resultt::SAFE:
114104
return a;
115105
case safety_checkert::resultt::ERROR:

src/goto-symex/goto_symex.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ class goto_symext
7070
log(mh),
7171
guard_identifier("goto_symex::\\guard"),
7272
path_storage(path_storage),
73+
path_segment_vccs(0),
7374
_total_vccs(std::numeric_limits<unsigned>::max()),
7475
_remaining_vccs(std::numeric_limits<unsigned>::max())
7576
{
@@ -464,6 +465,18 @@ class goto_symext
464465

465466
path_storaget &path_storage;
466467

468+
public:
469+
/// \brief Number of VCCs generated during the run of this goto_symext object
470+
///
471+
/// This member is always initialized to `0` upon construction of this object.
472+
/// It therefore differs from goto_symex_statet::total_vccs, which persists
473+
/// across the creation of several goto_symext objects. When CBMC is run in
474+
/// path-exploration mode, the meaning of this member is "the number of VCCs
475+
/// generated between the last branch point and the current instruction,"
476+
/// while goto_symex_statet::total_vccs records the total number of VCCs
477+
/// generated along the entire path from the beginning of the program.
478+
std::size_t path_segment_vccs;
479+
467480
protected:
468481
/// @{\name Statistics
469482
///

src/goto-symex/symex_main.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ void goto_symext::vcc(
5252
statet &state)
5353
{
5454
state.total_vccs++;
55+
path_segment_vccs++;
5556

5657
exprt expr=vcc_expr;
5758

unit/path_strategies.cpp

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -81,15 +81,13 @@ SCENARIO("path strategies")
8181
opts_callback,
8282
c,
8383
{symex_eventt::resume(symex_eventt::enumt::JUMP, 7),
84-
symex_eventt::result(symex_eventt::enumt::SUCCESS),
8584
symex_eventt::resume(symex_eventt::enumt::NEXT, 5),
8685
symex_eventt::result(symex_eventt::enumt::SUCCESS)});
8786
check_with_strategy(
8887
"fifo",
8988
opts_callback,
9089
c,
9190
{symex_eventt::resume(symex_eventt::enumt::NEXT, 5),
92-
symex_eventt::result(symex_eventt::enumt::SUCCESS),
9391
symex_eventt::resume(symex_eventt::enumt::JUMP, 7),
9492
symex_eventt::result(symex_eventt::enumt::SUCCESS)});
9593
}
@@ -125,14 +123,11 @@ SCENARIO("path strategies")
125123
{// Outer else, inner else
126124
symex_eventt::resume(symex_eventt::enumt::JUMP, 13),
127125
symex_eventt::resume(symex_eventt::enumt::JUMP, 16),
128-
symex_eventt::result(symex_eventt::enumt::SUCCESS),
129126
// Outer else, inner if
130127
symex_eventt::resume(symex_eventt::enumt::NEXT, 14),
131-
symex_eventt::result(symex_eventt::enumt::SUCCESS),
132128
// Outer if, inner else
133129
symex_eventt::resume(symex_eventt::enumt::NEXT, 6),
134130
symex_eventt::resume(symex_eventt::enumt::JUMP, 9),
135-
symex_eventt::result(symex_eventt::enumt::SUCCESS),
136131
// Outer if, inner if
137132
symex_eventt::resume(symex_eventt::enumt::NEXT, 7),
138133
symex_eventt::result(symex_eventt::enumt::SUCCESS)});
@@ -147,13 +142,9 @@ SCENARIO("path strategies")
147142
symex_eventt::resume(symex_eventt::enumt::JUMP, 13),
148143
// Expand inner if of the outer if
149144
symex_eventt::resume(symex_eventt::enumt::NEXT, 7),
150-
// No more branch points, so complete the path
151-
symex_eventt::result(symex_eventt::enumt::SUCCESS),
152-
// Continue BFSing
145+
// No more branch points, so complete the path. Then continue BFSing
153146
symex_eventt::resume(symex_eventt::enumt::JUMP, 9),
154-
symex_eventt::result(symex_eventt::enumt::SUCCESS),
155147
symex_eventt::resume(symex_eventt::enumt::NEXT, 14),
156-
symex_eventt::result(symex_eventt::enumt::SUCCESS),
157148
symex_eventt::resume(symex_eventt::enumt::JUMP, 16),
158149
symex_eventt::result(symex_eventt::enumt::SUCCESS)});
159150
}
@@ -199,6 +190,9 @@ SCENARIO("path strategies")
199190
// infeasible.
200191
symex_eventt::resume(symex_eventt::enumt::NEXT, 7),
201192
symex_eventt::result(symex_eventt::enumt::SUCCESS),
193+
194+
// Overall we fail.
195+
symex_eventt::result(symex_eventt::enumt::FAILURE),
202196
});
203197

204198
check_with_strategy(
@@ -224,6 +218,9 @@ SCENARIO("path strategies")
224218
// executing the loop once, decrementing x to 0; assert(x) should fail.
225219
symex_eventt::resume(symex_eventt::enumt::JUMP, 9),
226220
symex_eventt::result(symex_eventt::enumt::FAILURE),
221+
222+
// Overall we fail.
223+
symex_eventt::result(symex_eventt::enumt::FAILURE),
227224
});
228225
}
229226

@@ -253,6 +250,8 @@ SCENARIO("path strategies")
253250
{symex_eventt::resume(symex_eventt::enumt::JUMP, 7),
254251
symex_eventt::result(symex_eventt::enumt::FAILURE),
255252
symex_eventt::resume(symex_eventt::enumt::NEXT, 5),
253+
symex_eventt::result(symex_eventt::enumt::FAILURE),
254+
// Overall result
256255
symex_eventt::result(symex_eventt::enumt::FAILURE)});
257256
}
258257
GIVEN("stopping on failure")
@@ -262,6 +261,8 @@ SCENARIO("path strategies")
262261
halt_callback,
263262
c,
264263
{symex_eventt::resume(symex_eventt::enumt::JUMP, 7),
264+
symex_eventt::result(symex_eventt::enumt::FAILURE),
265+
// Overall result
265266
symex_eventt::result(symex_eventt::enumt::FAILURE)});
266267
}
267268
}
@@ -380,14 +381,20 @@ void _check_with_strategy(
380381
prop_convt &pc = cbmc_solver->prop_conv();
381382
std::function<bool(void)> callback = []() { return false; };
382383

384+
safety_checkert::resultt overall_result = safety_checkert::resultt::SAFE;
385+
std::size_t expected_results_cnt = 0;
386+
383387
bmct bmc(opts, gm.get_symbol_table(), mh, pc, *worklist, callback);
384-
safety_checkert::resultt result = bmc.run(gm);
388+
safety_checkert::resultt tmp_result = bmc.run(gm);
385389

386-
std::size_t expected_results_cnt = 0;
387-
symex_eventt::validate_result(events, result, expected_results_cnt);
390+
if(tmp_result != safety_checkert::resultt::PAUSED)
391+
{
392+
symex_eventt::validate_result(events, tmp_result, expected_results_cnt);
393+
overall_result &= tmp_result;
394+
}
388395

389396
if(
390-
result == safety_checkert::resultt::UNSAFE &&
397+
overall_result == safety_checkert::resultt::UNSAFE &&
391398
opts.get_bool_option("stop-on-fail") && opts.is_set("paths"))
392399
{
393400
worklist->clear();
@@ -411,17 +418,25 @@ void _check_with_strategy(
411418
resume.state,
412419
*worklist,
413420
callback);
414-
result = pe.run(gm);
421+
tmp_result = pe.run(gm);
415422

416-
symex_eventt::validate_result(events, result, expected_results_cnt);
423+
if(tmp_result != safety_checkert::resultt::PAUSED)
424+
{
425+
symex_eventt::validate_result(events, tmp_result, expected_results_cnt);
426+
overall_result &= tmp_result;
427+
}
417428
worklist->pop();
418429

419430
if(
420-
result == safety_checkert::resultt::UNSAFE &&
431+
overall_result == safety_checkert::resultt::UNSAFE &&
421432
opts.get_bool_option("stop-on-fail"))
422433
{
423434
worklist->clear();
424435
}
425436
}
437+
438+
symex_eventt::validate_result(events, overall_result, expected_results_cnt);
439+
440+
INFO("The expected results list contains " << events.size() << " items");
426441
REQUIRE(events.empty());
427442
}

0 commit comments

Comments
 (0)