48
48
49
49
#include < goto-instrument/full_slicer.h>
50
50
#include < goto-instrument/nondet_static.h>
51
- #include < goto-instrument/cover.h>
52
51
53
52
#include < pointer-analysis/add_failed_symbols.h>
54
53
@@ -378,6 +377,23 @@ void jbmc_parse_optionst::get_command_line_options(optionst &options)
378
377
cmdline.get_value (" symex-coverage-report" ));
379
378
380
379
PARSE_OPTIONS_GOTO_TRACE (cmdline, options);
380
+
381
+ if (cmdline.isset (" symex-driven-lazy-loading" ))
382
+ {
383
+ options.set_option (" symex-driven-lazy-loading" , true );
384
+ for (const char *opt :
385
+ { " nondet-static" ,
386
+ " full-slice" ,
387
+ " show-properties" ,
388
+ " lazy-methods" })
389
+ {
390
+ if (cmdline.isset (opt))
391
+ {
392
+ throw std::string (" Option " ) + opt +
393
+ " can't be used with --symex-driven-lazy-loading" ;
394
+ }
395
+ }
396
+ }
381
397
}
382
398
383
399
// / invoke main modules
@@ -472,24 +488,7 @@ int jbmc_parse_optionst::doit()
472
488
return 0 ;
473
489
}
474
490
475
- std::unique_ptr<goto_modelt> goto_model_ptr;
476
- int get_goto_program_ret=get_goto_program (goto_model_ptr, options);
477
- if (get_goto_program_ret!=-1 )
478
- return get_goto_program_ret;
479
-
480
- goto_modelt &goto_model = *goto_model_ptr;
481
-
482
- if (cmdline.isset (" show-properties" ))
483
- {
484
- show_properties (
485
- goto_model, get_message_handler (), ui_message_handler.get_ui ());
486
- return 0 ; // should contemplate EX_OK from sysexits.h
487
- }
488
-
489
- if (set_properties (goto_model))
490
- return 7 ; // should contemplate EX_USAGE from sysexits.h
491
-
492
- std::function<void (bmct &, const symbol_tablet &)> configure_bmc;
491
+ std::function<void (bmct &, const symbol_tablet &)> configure_bmc = nullptr ;
493
492
if (options.get_bool_option (" java-unwind-enum-static" ))
494
493
{
495
494
configure_bmc = [](
@@ -508,15 +507,76 @@ int jbmc_parse_optionst::doit()
508
507
});
509
508
};
510
509
}
510
+
511
+ if (!cmdline.isset (" symex-driven-lazy-loading" ))
512
+ {
513
+ std::unique_ptr<goto_modelt> goto_model_ptr;
514
+ int get_goto_program_ret=get_goto_program (goto_model_ptr, options);
515
+ if (get_goto_program_ret!=-1 )
516
+ return get_goto_program_ret;
517
+
518
+ goto_modelt &goto_model = *goto_model_ptr;
519
+
520
+ if (cmdline.isset (" show-properties" ))
521
+ {
522
+ show_properties (
523
+ goto_model, get_message_handler (), ui_message_handler.get_ui ());
524
+ return 0 ; // should contemplate EX_OK from sysexits.h
525
+ }
526
+
527
+ if (set_properties (goto_model))
528
+ return 7 ; // should contemplate EX_USAGE from sysexits.h
529
+
530
+ // The `configure_bmc` callback passed will enable enum-unwind-static if
531
+ // applicable.
532
+ return bmct::do_language_agnostic_bmc (
533
+ options, goto_model, ui_message_handler.get_ui (), *this , configure_bmc);
534
+ }
511
535
else
512
536
{
513
- configure_bmc = [](
514
- bmct &bmc, const symbol_tablet &symbol_table) { // NOLINT (*)
515
- // NOOP
537
+ // Use symex-driven lazy loading:
538
+ lazy_goto_modelt lazy_goto_model=lazy_goto_modelt::from_handler_object (
539
+ *this , options, get_message_handler ());
540
+ lazy_goto_model.initialize (cmdline);
541
+
542
+ // The precise wording of this error matches goto-symex's complaint when no
543
+ // __CPROVER_start exists (if we just go ahead and run it anyway it will
544
+ // trip an invariant when it tries to load it)
545
+ if (!lazy_goto_model.symbol_table .has_symbol (goto_functionst::entry_point ()))
546
+ {
547
+ error () << " the program has no entry point" ;
548
+ return 6 ;
549
+ }
550
+
551
+ // Add failed symbols for any symbol created prior to loading any
552
+ // particular function:
553
+ add_failed_symbols (lazy_goto_model.symbol_table );
554
+
555
+ // If applicable, parse the coverage instrumentation configuration, which
556
+ // will be used in process_goto_function:
557
+ cover_config =
558
+ get_cover_config (
559
+ options, lazy_goto_model.symbol_table , get_message_handler ());
560
+
561
+ // Provide show-goto-functions and similar dump functions after symex
562
+ // executes. If --paths is active, these dump routines run after every
563
+ // paths iteration. Its return value indicates that if we ran any dump
564
+ // function, then we should skip the actual solver phase.
565
+ auto callback_after_symex = [this , &lazy_goto_model]() { // NOLINT (*)
566
+ return show_loaded_functions (lazy_goto_model);
516
567
};
568
+
569
+ // The `configure_bmc` callback passed will enable enum-unwind-static if
570
+ // applicable.
571
+ return
572
+ bmct::do_language_agnostic_bmc (
573
+ options,
574
+ lazy_goto_model,
575
+ ui_message_handler.get_ui (),
576
+ *this ,
577
+ configure_bmc,
578
+ callback_after_symex);
517
579
}
518
- return bmct::do_language_agnostic_bmc (
519
- options, goto_model, ui_message_handler.get_ui (), *this , configure_bmc);
520
580
}
521
581
522
582
bool jbmc_parse_optionst::set_properties (goto_modelt &goto_model)
@@ -643,13 +703,30 @@ void jbmc_parse_optionst::process_goto_function(
643
703
journalling_symbol_tablet &symbol_table = function.get_symbol_table ();
644
704
namespacet ns (symbol_table);
645
705
goto_functionst::goto_functiont &goto_function = function.get_goto_function ();
706
+
707
+ bool using_symex_driven_loading =
708
+ options.get_bool_option (" symex-driven-lazy-loading" );
709
+
646
710
try
647
711
{
648
712
// Removal of RTTI inspection:
649
713
remove_instanceof (goto_function, symbol_table);
650
714
// Java virtual functions -> explicit dispatch tables:
651
715
remove_virtual_functions (function);
652
716
717
+ if (using_symex_driven_loading)
718
+ {
719
+ // remove exceptions
720
+ // If using symex-driven function loading we need to do this now so that
721
+ // symex doesn't have to cope with exception-handling constructs; however
722
+ // the results are slightly worse than running it in whole-program mode
723
+ // (e.g. dead catch sites will be retained)
724
+ remove_exceptions (
725
+ goto_function.body ,
726
+ symbol_table,
727
+ remove_exceptions_typest::REMOVE_ADDED_INSTANCEOF);
728
+ }
729
+
653
730
auto function_is_stub =
654
731
[&symbol_table, &model](const irep_idt &id) { // NOLINT(*)
655
732
return symbol_table.lookup_ref (id).value .is_nil () &&
@@ -699,6 +776,28 @@ void jbmc_parse_optionst::process_goto_function(
699
776
symbol_table);
700
777
}
701
778
779
+ // If using symex-driven function loading we must insert the coverage goals
780
+ // now so symex sees its targets; otherwise we leave this until
781
+ // process_goto_functions, as we haven't run remove_exceptions yet, and that
782
+ // pass alters the CFG.
783
+ if (using_symex_driven_loading)
784
+ {
785
+ // instrument cover goals
786
+ if (cmdline.isset (" cover" ))
787
+ {
788
+ INVARIANT (
789
+ cover_config != nullptr , " cover config should have been parsed" );
790
+ instrument_cover_goals (*cover_config, function, get_message_handler ());
791
+ }
792
+
793
+ // label the assertions
794
+ label_properties (goto_function.body );
795
+
796
+ goto_function.body .update ();
797
+ function.compute_location_numbers ();
798
+ goto_function.body .compute_loop_numbers ();
799
+ }
800
+
702
801
// update the function member in each instruction
703
802
function.update_instructions_function ();
704
803
}
@@ -722,14 +821,57 @@ void jbmc_parse_optionst::process_goto_function(
722
821
}
723
822
}
724
823
824
+ bool jbmc_parse_optionst::show_loaded_functions (
825
+ const abstract_goto_modelt &goto_model)
826
+ {
827
+ if (cmdline.isset (" show-symbol-table" ))
828
+ {
829
+ show_symbol_table (
830
+ goto_model.get_symbol_table (), ui_message_handler.get_ui ());
831
+ return true ;
832
+ }
833
+
834
+ if (cmdline.isset (" show-loops" ))
835
+ {
836
+ show_loop_ids (ui_message_handler.get_ui (), goto_model.get_goto_functions ());
837
+ return true ;
838
+ }
839
+
840
+ if (
841
+ cmdline.isset (" show-goto-functions" ) ||
842
+ cmdline.isset (" list-goto-functions" ))
843
+ {
844
+ namespacet ns (goto_model.get_symbol_table ());
845
+ show_goto_functions (
846
+ ns,
847
+ get_message_handler (),
848
+ ui_message_handler.get_ui (),
849
+ goto_model.get_goto_functions (),
850
+ cmdline.isset (" list-goto-functions" ));
851
+ return true ;
852
+ }
853
+
854
+ return false ;
855
+ }
856
+
725
857
bool jbmc_parse_optionst::process_goto_functions (
726
858
goto_modelt &goto_model,
727
859
const optionst &options)
728
860
{
729
861
try
730
862
{
731
863
status () << " Running GOTO functions transformation passes" << eom;
732
- // remove catch and throw (introduces instanceof but request it is removed)
864
+
865
+ bool using_symex_driven_loading =
866
+ options.get_bool_option (" symex-driven-lazy-loading" );
867
+
868
+ // When using symex-driven lazy loading, *all* relevant processing is done
869
+ // during process_goto_function, so we have nothing to do here.
870
+ if (using_symex_driven_loading)
871
+ return false ;
872
+
873
+ // remove catch and throw
874
+ // (introduces instanceof but request it is removed)
733
875
remove_exceptions (
734
876
goto_model, remove_exceptions_typest::REMOVE_ADDED_INSTANCEOF);
735
877
@@ -865,6 +1007,8 @@ void jbmc_parse_optionst::help()
865
1007
// This one is handled by jbmc_parse_options not by the Java frontend,
866
1008
// hence its presence here:
867
1009
" --java-unwind-enum-static try to unwind loops in static initialization of enums\n " // NOLINT(*)
1010
+ // Currently only supported in the JBMC frontend:
1011
+ " --symex-driven-lazy-loading only load functions when first entered by symbolic execution\n " // NOLINT(*)
868
1012
" \n "
869
1013
" BMC options:\n "
870
1014
HELP_BMC
0 commit comments