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,9 @@ 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 ),
189
+
178
190
// The path where x != 1 and we have nothing to check:
179
191
symex_eventt::resume (symex_eventt::enumt::JUMP, 11 ),
180
192
@@ -204,6 +216,9 @@ SCENARIO("path strategies")
204
216
opts_callback,
205
217
c,
206
218
{
219
+ // Entry state is line 0
220
+ symex_eventt::resume (symex_eventt::enumt::NEXT, 0 ),
221
+
207
222
// First the path where we enter the if-block at line 4 then on hitting
208
223
// the branch at line 6 consider skipping straight to the end, but find
209
224
// nothing there to investigate:
@@ -257,7 +272,9 @@ SCENARIO("path strategies")
257
272
" lifo" ,
258
273
no_halt_callback,
259
274
c,
260
- {symex_eventt::resume (symex_eventt::enumt::JUMP, 7 ),
275
+ {// Entry state is line 0
276
+ symex_eventt::resume (symex_eventt::enumt::NEXT, 0 ),
277
+ symex_eventt::resume (symex_eventt::enumt::JUMP, 7 ),
261
278
symex_eventt::result (symex_eventt::enumt::FAILURE),
262
279
symex_eventt::resume (symex_eventt::enumt::NEXT, 5 ),
263
280
symex_eventt::result (symex_eventt::enumt::FAILURE),
@@ -270,7 +287,9 @@ SCENARIO("path strategies")
270
287
" lifo" ,
271
288
halt_callback,
272
289
c,
273
- {symex_eventt::resume (symex_eventt::enumt::JUMP, 7 ),
290
+ {// Entry state is line 0
291
+ symex_eventt::resume (symex_eventt::enumt::NEXT, 0 ),
292
+ symex_eventt::resume (symex_eventt::enumt::JUMP, 7 ),
274
293
symex_eventt::result (symex_eventt::enumt::FAILURE),
275
294
// Overall result
276
295
symex_eventt::result (symex_eventt::enumt::FAILURE)});
@@ -283,24 +302,24 @@ SCENARIO("path strategies")
283
302
284
303
void symex_eventt::validate_result (
285
304
listt &events,
286
- const safety_checkert ::resultt result,
305
+ const incremental_goto_checkert ::resultt::progresst result,
287
306
std::size_t &counter)
288
307
{
289
308
INFO (
290
309
" Expecting result to be '"
291
- << (result == safety_checkert::resultt::SAFE ? " success" : " failure" )
310
+ << (result == incremental_goto_checkert::resultt::progresst::DONE
311
+ ? " success"
312
+ : " failure" )
292
313
<< " ' (item at index [" << counter << " ] in expected results list" );
293
314
++counter;
294
315
295
- REQUIRE (result != safety_checkert::resultt::ERROR);
296
-
297
- if (result == safety_checkert::resultt::SAFE)
316
+ if (result == incremental_goto_checkert::resultt::progresst::DONE)
298
317
{
299
318
REQUIRE (!events.empty ());
300
319
REQUIRE (events.front ().first == symex_eventt::enumt::SUCCESS);
301
320
events.pop_front ();
302
321
}
303
- else if (result == safety_checkert::resultt::UNSAFE)
322
+ else
304
323
{
305
324
REQUIRE (!events.empty ());
306
325
REQUIRE (events.front ().first == symex_eventt::enumt::FAILURE);
@@ -315,23 +334,25 @@ void symex_eventt::validate_resume(
315
334
{
316
335
REQUIRE (!events.empty ());
317
336
318
- int dst = std::stoi (state.saved_target ->source_location .get_line ().c_str ());
337
+ int dst = 0 ;
338
+ if (!state.saved_target ->source_location .get_line ().empty ())
339
+ dst = std::stoi (state.saved_target ->source_location .get_line ().c_str ());
319
340
320
- if (state.has_saved_jump_target )
341
+ if (state.has_saved_next_instruction )
321
342
{
322
343
INFO (
323
- " Expecting resume to be 'jump ' to line "
344
+ " Expecting resume to be 'next ' to line "
324
345
<< dst << " (item at index [" << counter
325
346
<< " ] in expected resumes list)" );
326
- REQUIRE (events.front ().first == symex_eventt::enumt::JUMP );
347
+ REQUIRE (events.front ().first == symex_eventt::enumt::NEXT );
327
348
}
328
- else if (state.has_saved_next_instruction )
349
+ else if (state.has_saved_jump_target )
329
350
{
330
351
INFO (
331
- " Expecting resume to be 'next ' to line "
352
+ " Expecting resume to be 'jump ' to line "
332
353
<< dst << " (item at index [" << counter
333
354
<< " ] in expected resumes list)" );
334
- REQUIRE (events.front ().first == symex_eventt::enumt::NEXT );
355
+ REQUIRE (events.front ().first == symex_eventt::enumt::JUMP );
335
356
}
336
357
else
337
358
REQUIRE (false );
@@ -342,11 +363,8 @@ void symex_eventt::validate_resume(
342
363
events.pop_front ();
343
364
}
344
365
345
- // This is a simplified version of bmct::do_language_agnostic_bmc, without all
346
- // the edge cases to deal with java programs, bytecode loaded on demand, etc. We
347
- // need to replicate some of this stuff because the worklist is a local variable
348
- // of do_language_agnostic_bmc, and we need to check the worklist every time
349
- // symex returns.
366
+ // This is a simplified copy of single_path_symex_checkert
367
+ // because we have to check the worklist every time goto-symex returns.
350
368
void _check_with_strategy (
351
369
const std::string &strategy,
352
370
const std::string &program,
@@ -366,95 +384,122 @@ void _check_with_strategy(
366
384
config.main = " main" ;
367
385
config.set (cmdline);
368
386
369
- optionst opts;
370
- cbmc_parse_optionst::set_default_options (opts);
371
- opts.set_option (" paths" , true );
372
- opts.set_option (" exploration-strategy" , strategy);
373
-
374
- opts_callback (opts);
375
-
376
- ui_message_handlert mh (cmdline, " path-explore" );
377
- mh.set_verbosity (0 );
378
- messaget log (mh);
379
-
387
+ optionst options;
388
+ cbmc_parse_optionst::set_default_options (options);
389
+ options.set_option (" paths" , true );
390
+ options.set_option (" exploration-strategy" , strategy);
380
391
REQUIRE (is_valid_path_strategy (strategy));
381
- std::unique_ptr<path_storaget> worklist = get_path_strategy (strategy);
382
- guard_managert guard_manager;
392
+ opts_callback (options);
383
393
384
- goto_modelt gm;
394
+ ui_message_handlert ui_message_handler (cmdline, " path-explore" );
395
+ ui_message_handler.set_verbosity (0 );
396
+ messaget log (ui_message_handler);
397
+
398
+ goto_modelt goto_model;
385
399
int ret;
386
- ret = cbmc_parse_optionst::get_goto_program (gm, opts, cmdline, log , mh);
400
+ ret = cbmc_parse_optionst::get_goto_program (
401
+ goto_model, options, cmdline, log , ui_message_handler);
387
402
REQUIRE (ret == -1 );
388
403
389
- namespacet ns (gm.get_symbol_table ());
390
- solver_factoryt solver_factory (opts, ns, mh, false );
391
- std::unique_ptr<solver_factoryt::solvert> cbmc_solver =
392
- solver_factory.get_solver ();
393
- prop_convt &initial_pc = cbmc_solver->prop_conv ();
394
- std::function<bool (void )> callback = []() { return false ; };
395
-
396
- safety_checkert::resultt overall_result = safety_checkert::resultt::SAFE;
397
- std::size_t expected_results_cnt = 0 ;
404
+ symbol_tablet symex_symbol_table;
405
+ namespacet ns (goto_model.get_symbol_table (), symex_symbol_table);
406
+ propertiest properties (initialize_properties (goto_model));
407
+ std::unique_ptr<path_storaget> worklist = get_path_strategy (strategy);
408
+ guard_managert guard_manager;
398
409
399
- bmct bmc (
400
- opts,
401
- gm.get_symbol_table (),
402
- mh,
403
- initial_pc,
404
- *worklist,
405
- callback,
406
- guard_manager);
407
- safety_checkert::resultt tmp_result = bmc.run (gm);
408
-
409
- if (tmp_result != safety_checkert::resultt::PAUSED)
410
410
{
411
- symex_eventt::validate_result (events, tmp_result, expected_results_cnt);
412
- overall_result &= tmp_result;
413
- }
411
+ // Put initial state into the work list
412
+ symex_target_equationt equation (ui_message_handler);
413
+ symex_bmct symex (
414
+ ui_message_handler,
415
+ goto_model.get_symbol_table (),
416
+ equation,
417
+ options,
418
+ *worklist,
419
+ guard_manager);
420
+ setup_symex (symex, ns, options, ui_message_handler);
414
421
415
- if (
416
- overall_result == safety_checkert::resultt::UNSAFE &&
417
- opts.get_bool_option (" stop-on-fail" ) && opts.is_set (" paths" ))
418
- {
419
- worklist->clear ();
422
+ symex.initialize_path_storage_from_entry_point_of (
423
+ goto_symext::get_goto_function (goto_model), symex_symbol_table);
420
424
}
421
425
426
+ std::size_t expected_results_cnt = 0 ;
422
427
while (!worklist->empty ())
423
428
{
424
- cbmc_solver = solver_factory.get_solver ();
425
- prop_convt &pc = cbmc_solver->prop_conv ();
426
429
path_storaget::patht &resume = worklist->peek ();
427
430
428
431
symex_eventt::validate_resume (events, resume.state , expected_results_cnt);
429
432
430
- path_explorert pe (
431
- opts,
432
- gm.get_symbol_table (),
433
- mh,
434
- pc,
433
+ symex_bmct symex (
434
+ ui_message_handler,
435
+ goto_model.get_symbol_table (),
435
436
resume.equation ,
436
- resume. state ,
437
+ options ,
437
438
*worklist,
438
- guard_manager,
439
- callback);
440
- tmp_result = pe.run (gm);
439
+ guard_manager);
440
+ setup_symex (symex, ns, options, ui_message_handler);
441
+
442
+ symex.resume_symex_from_saved_state (
443
+ goto_symext::get_goto_function (goto_model),
444
+ resume.state ,
445
+ &resume.equation ,
446
+ symex_symbol_table);
447
+ postprocess_equation (
448
+ symex, resume.equation , options, ns, ui_message_handler);
441
449
442
- if (tmp_result != safety_checkert::resultt::PAUSED)
450
+ incremental_goto_checkert::resultt result (
451
+ incremental_goto_checkert::resultt::progresst::DONE);
452
+
453
+ if (symex.get_remaining_vccs () > 0 )
443
454
{
444
- symex_eventt::validate_result (events, tmp_result, expected_results_cnt);
445
- overall_result &= tmp_result;
455
+ update_properties_status_from_symex_target_equation (
456
+ properties, result.updated_properties , resume.equation );
457
+
458
+ goto_symex_property_decidert property_decider (
459
+ options, ui_message_handler, resume.equation , ns);
460
+
461
+ const auto solver_runtime = prepare_property_decider (
462
+ properties, resume.equation , property_decider, ui_message_handler);
463
+
464
+ run_property_decider (
465
+ result,
466
+ properties,
467
+ property_decider,
468
+ ui_message_handler,
469
+ solver_runtime,
470
+ false );
471
+
472
+ symex_eventt::validate_result (
473
+ events, result.progress , expected_results_cnt);
446
474
}
475
+
447
476
worklist->pop ();
448
477
449
478
if (
450
- overall_result == safety_checkert::resultt::UNSAFE &&
451
- opts.get_bool_option (" stop-on-fail" ))
479
+ result.progress ==
480
+ incremental_goto_checkert::resultt::progresst::FOUND_FAIL &&
481
+ options.get_bool_option (" stop-on-fail" ))
452
482
{
453
483
worklist->clear ();
454
484
}
485
+
486
+ if (worklist->empty ())
487
+ {
488
+ update_status_of_not_checked_properties (
489
+ properties, result.updated_properties );
490
+
491
+ update_status_of_unknown_properties (
492
+ properties, result.updated_properties );
493
+ }
455
494
}
456
495
457
- symex_eventt::validate_result (events, overall_result, expected_results_cnt);
496
+ const resultt overall_result = determine_result (properties);
497
+ symex_eventt::validate_result (
498
+ events,
499
+ overall_result == resultt::FAIL
500
+ ? incremental_goto_checkert::resultt::progresst::FOUND_FAIL
501
+ : incremental_goto_checkert::resultt::progresst::DONE,
502
+ expected_results_cnt);
458
503
459
504
INFO (" The expected results list contains " << events.size () << " items" );
460
505
REQUIRE (events.empty ());
0 commit comments