Skip to content

Commit 0ed6d89

Browse files
committed
JBMC: use symex-driven lazy loading
This adds the symex-driven-lazy-loading option, which causes functions to be loaded only when symex first requests their body. This means that all frontend effort can be saved relating to functions that symex reveals to be inaccessible, such as virtual function calls whose full array of possible targets are known to be unreachable as a result of value-set analysis on the type of the callee instance.
1 parent 6222487 commit 0ed6d89

File tree

2 files changed

+170
-26
lines changed

2 files changed

+170
-26
lines changed

src/jbmc/jbmc_parse_options.cpp

Lines changed: 165 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ Author: Daniel Kroening, kroening@kroening.com
4848

4949
#include <goto-instrument/full_slicer.h>
5050
#include <goto-instrument/nondet_static.h>
51-
#include <goto-instrument/cover.h>
5251

5352
#include <pointer-analysis/add_failed_symbols.h>
5453

@@ -378,6 +377,23 @@ void jbmc_parse_optionst::get_command_line_options(optionst &options)
378377
cmdline.get_value("symex-coverage-report"));
379378

380379
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+
}
381397
}
382398

383399
/// invoke main modules
@@ -472,24 +488,7 @@ int jbmc_parse_optionst::doit()
472488
return 0;
473489
}
474490

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;
493492
if(options.get_bool_option("java-unwind-enum-static"))
494493
{
495494
configure_bmc = [](
@@ -508,15 +507,72 @@ int jbmc_parse_optionst::doit()
508507
});
509508
};
510509
}
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+
return bmct::do_language_agnostic_bmc(
531+
options, goto_model, ui_message_handler.get_ui(), *this, configure_bmc);
532+
}
511533
else
512534
{
513-
configure_bmc = [](
514-
bmct &bmc, const symbol_tablet &symbol_table) { // NOLINT (*)
515-
// NOOP
535+
// Use symex-driven lazy loading:
536+
lazy_goto_modelt lazy_goto_model=lazy_goto_modelt::from_handler_object(
537+
*this, options, get_message_handler());
538+
lazy_goto_model.initialize(cmdline);
539+
540+
// The precise wording of this error matches goto-symex's complaint when no
541+
// __CPROVER_start exists (if we just go ahead and run it anyway it will
542+
// trip an invariant when it tries to load it)
543+
if(!lazy_goto_model.symbol_table.has_symbol(goto_functionst::entry_point()))
544+
{
545+
error() << "the program has no entry point";
546+
return 6;
547+
}
548+
549+
// Add failed symbols for any symbol created prior to loading any
550+
// particular function:
551+
add_failed_symbols(lazy_goto_model.symbol_table);
552+
553+
// If applicable, parse the coverage instrumentation configuration, which
554+
// will be used in process_goto_function:
555+
cover_config =
556+
get_cover_config(
557+
options, lazy_goto_model.symbol_table, get_message_handler());
558+
559+
// Provide show-goto-functions and similar dump functions after symex
560+
// executes. If --paths is active, these dump routines run after every
561+
// paths iteration. Its return value indicates that if we ran any dump
562+
// function, then we should skip the actual solver phase.
563+
auto callback_after_symex = [this, &lazy_goto_model]() { // NOLINT (*)
564+
return show_loaded_functions(lazy_goto_model);
516565
};
566+
567+
return
568+
bmct::do_language_agnostic_bmc(
569+
options,
570+
lazy_goto_model,
571+
ui_message_handler.get_ui(),
572+
*this,
573+
configure_bmc,
574+
callback_after_symex);
517575
}
518-
return bmct::do_language_agnostic_bmc(
519-
options, goto_model, ui_message_handler.get_ui(), *this, configure_bmc);
520576
}
521577

522578
bool jbmc_parse_optionst::set_properties(goto_modelt &goto_model)
@@ -643,13 +699,30 @@ void jbmc_parse_optionst::process_goto_function(
643699
journalling_symbol_tablet &symbol_table = function.get_symbol_table();
644700
namespacet ns(symbol_table);
645701
goto_functionst::goto_functiont &goto_function = function.get_goto_function();
702+
703+
bool using_symex_driven_loading =
704+
options.get_bool_option("symex-driven-lazy-loading");
705+
646706
try
647707
{
648708
// Removal of RTTI inspection:
649709
remove_instanceof(goto_function, symbol_table);
650710
// Java virtual functions -> explicit dispatch tables:
651711
remove_virtual_functions(function);
652712

713+
if(using_symex_driven_loading)
714+
{
715+
// remove exceptions
716+
// If using symex-driven function loading we need to do this now so that
717+
// symex doesn't have to cope with exception-handling constructs; however
718+
// the results are slightly worse than running it in whole-program mode
719+
// (e.g. dead catch sites will be retained)
720+
remove_exceptions(
721+
goto_function.body,
722+
symbol_table,
723+
remove_exceptions_typest::REMOVE_ADDED_INSTANCEOF);
724+
}
725+
653726
auto function_is_stub =
654727
[&symbol_table, &model](const irep_idt &id) { // NOLINT(*)
655728
return symbol_table.lookup_ref(id).value.is_nil() &&
@@ -699,6 +772,28 @@ void jbmc_parse_optionst::process_goto_function(
699772
symbol_table);
700773
}
701774

775+
// If using symex-driven function loading we must insert the coverage goals
776+
// now so symex sees its targets; otherwise we leave this until
777+
// process_goto_functions, as we haven't run remove_exceptions yet, and that
778+
// pass alters the CFG.
779+
if(using_symex_driven_loading)
780+
{
781+
// instrument cover goals
782+
if(cmdline.isset("cover"))
783+
{
784+
INVARIANT(
785+
cover_config != nullptr, "cover config should have been parsed");
786+
instrument_cover_goals(*cover_config, function, get_message_handler());
787+
}
788+
789+
// label the assertions
790+
label_properties(goto_function.body);
791+
792+
goto_function.body.update();
793+
function.compute_location_numbers();
794+
goto_function.body.compute_loop_numbers();
795+
}
796+
702797
// update the function member in each instruction
703798
function.update_instructions_function();
704799
}
@@ -722,14 +817,57 @@ void jbmc_parse_optionst::process_goto_function(
722817
}
723818
}
724819

820+
bool jbmc_parse_optionst::show_loaded_functions(
821+
const abstract_goto_modelt &goto_model)
822+
{
823+
if(cmdline.isset("show-symbol-table"))
824+
{
825+
show_symbol_table(
826+
goto_model.get_symbol_table(), ui_message_handler.get_ui());
827+
return true;
828+
}
829+
830+
if(cmdline.isset("show-loops"))
831+
{
832+
show_loop_ids(ui_message_handler.get_ui(), goto_model.get_goto_functions());
833+
return true;
834+
}
835+
836+
if(
837+
cmdline.isset("show-goto-functions") ||
838+
cmdline.isset("list-goto-functions"))
839+
{
840+
namespacet ns(goto_model.get_symbol_table());
841+
show_goto_functions(
842+
ns,
843+
get_message_handler(),
844+
ui_message_handler.get_ui(),
845+
goto_model.get_goto_functions(),
846+
cmdline.isset("list-goto-functions"));
847+
return true;
848+
}
849+
850+
return false;
851+
}
852+
725853
bool jbmc_parse_optionst::process_goto_functions(
726854
goto_modelt &goto_model,
727855
const optionst &options)
728856
{
729857
try
730858
{
731859
status() << "Running GOTO functions transformation passes" << eom;
732-
// remove catch and throw (introduces instanceof but request it is removed)
860+
861+
bool using_symex_driven_loading =
862+
options.get_bool_option("symex-driven-lazy-loading");
863+
864+
// When using symex-driven lazy loading, *all* relevant processing is done
865+
// during process_goto_function, so we have nothing to do here.
866+
if(using_symex_driven_loading)
867+
return false;
868+
869+
// remove catch and throw
870+
// (introduces instanceof but request it is removed)
733871
remove_exceptions(
734872
goto_model, remove_exceptions_typest::REMOVE_ADDED_INSTANCEOF);
735873

@@ -865,6 +1003,8 @@ void jbmc_parse_optionst::help()
8651003
// This one is handled by jbmc_parse_options not by the Java frontend,
8661004
// hence its presence here:
8671005
" --java-unwind-enum-static try to unwind loops in static initialization of enums\n" // NOLINT(*)
1006+
// Currently only supported in the JBMC frontend:
1007+
" --symex-driven-lazy-loading only load functions when first entered by symbolic execution\n" // NOLINT(*)
8681008
"\n"
8691009
"BMC options:\n"
8701010
HELP_BMC

src/jbmc/jbmc_parse_options.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ Author: Daniel Kroening, kroening@kroening.com
2525
#include <goto-programs/goto_trace.h>
2626
#include <goto-programs/lazy_goto_model.h>
2727
#include <goto-programs/show_properties.h>
28+
#include <goto-instrument/cover.h>
2829

2930
#include <java_bytecode/java_bytecode_language.h>
3031

@@ -72,7 +73,8 @@ class optionst;
7273
JAVA_BYTECODE_LANGUAGE_OPTIONS \
7374
"(java-unwind-enum-static)" \
7475
"(localize-faults)(localize-faults-method):" \
75-
OPT_GOTO_TRACE
76+
OPT_GOTO_TRACE \
77+
"(symex-driven-lazy-loading)"
7678
// clang-format on
7779

7880
class jbmc_parse_optionst:
@@ -97,11 +99,13 @@ class jbmc_parse_optionst:
9799

98100
protected:
99101
ui_message_handlert ui_message_handler;
102+
std::unique_ptr<cover_configt> cover_config;
100103

101104
void eval_verbosity();
102105
void get_command_line_options(optionst &);
103106
int get_goto_program(
104107
std::unique_ptr<goto_modelt> &goto_model, const optionst &);
108+
bool show_loaded_functions(const abstract_goto_modelt &goto_model);
105109

106110
bool set_properties(goto_modelt &goto_model);
107111
};

0 commit comments

Comments
 (0)