16
16
17
17
#include < ansi-c/ansi_c_language.h>
18
18
19
- #include < cbmc/bmc.h>
20
19
#include < cbmc/cbmc_parse_options.h>
21
20
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>
23
24
24
25
#include < langapi/mode.h>
25
26
42
43
// `goto` instruction.
43
44
//
44
45
// 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
47
48
// path.
48
49
//
49
50
// To figure out what the events should be, run CBMC on the test program with
@@ -80,14 +81,18 @@ SCENARIO("path strategies")
80
81
" lifo" ,
81
82
opts_callback,
82
83
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 ),
84
87
symex_eventt::resume (symex_eventt::enumt::NEXT, 5 ),
85
88
symex_eventt::result (symex_eventt::enumt::SUCCESS)});
86
89
check_with_strategy (
87
90
" fifo" ,
88
91
opts_callback,
89
92
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 ),
91
96
symex_eventt::resume (symex_eventt::enumt::JUMP, 7 ),
92
97
symex_eventt::result (symex_eventt::enumt::SUCCESS)});
93
98
}
@@ -120,7 +125,9 @@ SCENARIO("path strategies")
120
125
" lifo" ,
121
126
opts_callback,
122
127
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
124
131
symex_eventt::resume (symex_eventt::enumt::JUMP, 13 ),
125
132
symex_eventt::resume (symex_eventt::enumt::JUMP, 16 ),
126
133
// Outer else, inner if
@@ -136,7 +143,9 @@ SCENARIO("path strategies")
136
143
" fifo" ,
137
144
opts_callback,
138
145
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
140
149
symex_eventt::resume (symex_eventt::enumt::NEXT, 6 ),
141
150
// Jump to outer else, but again don't continue depth-first
142
151
symex_eventt::resume (symex_eventt::enumt::JUMP, 13 ),
@@ -175,6 +184,8 @@ SCENARIO("path strategies")
175
184
opts_callback,
176
185
c,
177
186
{
187
+ // Entry state is line 0
188
+ symex_eventt::resume (symex_eventt::enumt::NEXT, 0 ),
178
189
// The path where we skip the loop body. Successful because the path is
179
190
// implausible, we cannot have skipped the body if x == 1.
180
191
symex_eventt::resume (symex_eventt::enumt::JUMP, 9 ),
@@ -200,6 +211,8 @@ SCENARIO("path strategies")
200
211
opts_callback,
201
212
c,
202
213
{
214
+ // Entry state is line 0
215
+ symex_eventt::resume (symex_eventt::enumt::NEXT, 0 ),
203
216
// The path where we skip the loop body. Successful because the path is
204
217
// implausible, we cannot have skipped the body if x == 1.
205
218
//
@@ -247,7 +260,9 @@ SCENARIO("path strategies")
247
260
" lifo" ,
248
261
no_halt_callback,
249
262
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 ),
251
266
symex_eventt::result (symex_eventt::enumt::FAILURE),
252
267
symex_eventt::resume (symex_eventt::enumt::NEXT, 5 ),
253
268
symex_eventt::result (symex_eventt::enumt::FAILURE),
@@ -260,7 +275,9 @@ SCENARIO("path strategies")
260
275
" lifo" ,
261
276
halt_callback,
262
277
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 ),
264
281
symex_eventt::result (symex_eventt::enumt::FAILURE),
265
282
// Overall result
266
283
symex_eventt::result (symex_eventt::enumt::FAILURE)});
@@ -273,24 +290,24 @@ SCENARIO("path strategies")
273
290
274
291
void symex_eventt::validate_result (
275
292
listt &events,
276
- const safety_checkert ::resultt result,
293
+ const incremental_goto_checkert ::resultt::progresst result,
277
294
std::size_t &counter)
278
295
{
279
296
INFO (
280
297
" Expecting result to be '"
281
- << (result == safety_checkert::resultt::SAFE ? " success" : " failure" )
298
+ << (result == incremental_goto_checkert::resultt::progresst::DONE
299
+ ? " success"
300
+ : " failure" )
282
301
<< " ' (item at index [" << counter << " ] in expected results list" );
283
302
++counter;
284
303
285
- REQUIRE (result != safety_checkert::resultt::ERROR);
286
-
287
- if (result == safety_checkert::resultt::SAFE)
304
+ if (result == incremental_goto_checkert::resultt::progresst::DONE)
288
305
{
289
306
REQUIRE (!events.empty ());
290
307
REQUIRE (events.front ().first == symex_eventt::enumt::SUCCESS);
291
308
events.pop_front ();
292
309
}
293
- else if (result == safety_checkert::resultt::UNSAFE)
310
+ else
294
311
{
295
312
REQUIRE (!events.empty ());
296
313
REQUIRE (events.front ().first == symex_eventt::enumt::FAILURE);
@@ -305,23 +322,25 @@ void symex_eventt::validate_resume(
305
322
{
306
323
REQUIRE (!events.empty ());
307
324
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 ());
309
328
310
- if (state.has_saved_jump_target )
329
+ if (state.has_saved_next_instruction )
311
330
{
312
331
INFO (
313
- " Expecting resume to be 'jump ' to line "
314
- << dst << " (item at index [" << counter
315
- << " ] in expected resumes list)" );
316
- REQUIRE (events.front ().first == symex_eventt::enumt::JUMP );
332
+ " Expecting resume to be 'next ' to line "
333
+ << dst << " (item at index [" << counter
334
+ << " ] in expected resumes list)" );
335
+ REQUIRE (events.front ().first == symex_eventt::enumt::NEXT );
317
336
}
318
- else if (state.has_saved_next_instruction )
337
+ else if (state.has_saved_jump_target )
319
338
{
320
339
INFO (
321
- " Expecting resume to be 'next ' to line "
340
+ " Expecting resume to be 'jump ' to line "
322
341
<< dst << " (item at index [" << counter
323
342
<< " ] in expected resumes list)" );
324
- REQUIRE (events.front ().first == symex_eventt::enumt::NEXT );
343
+ REQUIRE (events.front ().first == symex_eventt::enumt::JUMP );
325
344
}
326
345
else
327
346
REQUIRE (false );
@@ -332,11 +351,8 @@ void symex_eventt::validate_resume(
332
351
events.pop_front ();
333
352
}
334
353
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.
340
356
void _check_with_strategy (
341
357
const std::string &strategy,
342
358
const std::string &program,
@@ -356,95 +372,122 @@ void _check_with_strategy(
356
372
config.main = " main" ;
357
373
config.set (cmdline);
358
374
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);
370
379
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);
373
381
374
- goto_modelt gm;
382
+ ui_message_handlert ui_message_handler (cmdline, " path-explore" );
383
+ ui_message_handler.set_verbosity (0 );
384
+ messaget log (ui_message_handler);
385
+
386
+ goto_modelt goto_model;
375
387
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);
377
390
REQUIRE (ret == -1 );
378
391
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;
388
397
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)
400
398
{
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);
404
409
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);
410
412
}
411
413
414
+ std::size_t expected_results_cnt = 0 ;
412
415
while (!worklist->empty ())
413
416
{
414
- cbmc_solver = solver_factory.get_solver ();
415
- prop_convt &pc = cbmc_solver->prop_conv ();
416
417
path_storaget::patht &resume = worklist->peek ();
417
418
418
419
symex_eventt::validate_resume (events, resume.state , expected_results_cnt);
419
420
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 (),
425
424
resume.equation ,
426
- resume. state ,
425
+ options ,
427
426
*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);
431
437
432
- if (tmp_result != safety_checkert::resultt::PAUSED)
438
+ incremental_goto_checkert::resultt result (
439
+ incremental_goto_checkert::resultt::progresst::DONE);
440
+
441
+ if (symex.get_remaining_vccs () > 0 )
433
442
{
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);
436
462
}
463
+
437
464
worklist->pop ();
438
465
439
466
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" ))
442
470
{
443
471
worklist->clear ();
444
472
}
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
+ }
445
482
}
446
483
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);
448
491
449
492
INFO (" The expected results list contains " << events.size () << " items" );
450
493
REQUIRE (events.empty ());
0 commit comments