Skip to content

Commit 7b5d73b

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 978ca5b commit 7b5d73b

File tree

2 files changed

+174
-26
lines changed

2 files changed

+174
-26
lines changed

src/jbmc/jbmc_parse_options.cpp

+169-25
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ Author: Daniel Kroening, [email protected]
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,76 @@ 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+
// 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+
}
511535
else
512536
{
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);
516567
};
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);
517579
}
518-
return bmct::do_language_agnostic_bmc(
519-
options, goto_model, ui_message_handler.get_ui(), *this, configure_bmc);
520580
}
521581

522582
bool jbmc_parse_optionst::set_properties(goto_modelt &goto_model)
@@ -643,13 +703,30 @@ void jbmc_parse_optionst::process_goto_function(
643703
journalling_symbol_tablet &symbol_table = function.get_symbol_table();
644704
namespacet ns(symbol_table);
645705
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+
646710
try
647711
{
648712
// Removal of RTTI inspection:
649713
remove_instanceof(goto_function, symbol_table);
650714
// Java virtual functions -> explicit dispatch tables:
651715
remove_virtual_functions(function);
652716

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+
653730
auto function_is_stub =
654731
[&symbol_table, &model](const irep_idt &id) { // NOLINT(*)
655732
return symbol_table.lookup_ref(id).value.is_nil() &&
@@ -699,6 +776,28 @@ void jbmc_parse_optionst::process_goto_function(
699776
symbol_table);
700777
}
701778

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+
702801
// update the function member in each instruction
703802
function.update_instructions_function();
704803
}
@@ -722,14 +821,57 @@ void jbmc_parse_optionst::process_goto_function(
722821
}
723822
}
724823

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+
725857
bool jbmc_parse_optionst::process_goto_functions(
726858
goto_modelt &goto_model,
727859
const optionst &options)
728860
{
729861
try
730862
{
731863
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)
733875
remove_exceptions(
734876
goto_model, remove_exceptions_typest::REMOVE_ADDED_INSTANCEOF);
735877

@@ -865,6 +1007,8 @@ void jbmc_parse_optionst::help()
8651007
// This one is handled by jbmc_parse_options not by the Java frontend,
8661008
// hence its presence here:
8671009
" --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(*)
8681012
"\n"
8691013
"BMC options:\n"
8701014
HELP_BMC

src/jbmc/jbmc_parse_options.h

+5-1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ Author: Daniel Kroening, [email protected]
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)