Merge pull request #4217 from peterschrammel/move-bmct-jbmc
Move cbmc/bmc and all_properties to jbmc
This commit is contained in:
commit
2e04b54cfc
|
@ -1,4 +1,6 @@
|
|||
SRC = jbmc_main.cpp \
|
||||
SRC = all_properties.cpp \
|
||||
bmc.cpp \
|
||||
jbmc_main.cpp \
|
||||
jbmc_parse_options.cpp \
|
||||
# Empty last line
|
||||
|
||||
|
@ -39,8 +41,6 @@ OBJ += ../$(CPROVER_DIR)/src/ansi-c/ansi-c$(LIBEXT) \
|
|||
../$(CPROVER_DIR)/src/util/util$(LIBEXT) \
|
||||
../miniz/miniz$(OBJEXT) \
|
||||
../$(CPROVER_DIR)/src/json/json$(LIBEXT) \
|
||||
../$(CPROVER_DIR)/src/cbmc/all_properties$(OBJEXT) \
|
||||
../$(CPROVER_DIR)/src/cbmc/bmc$(OBJEXT) \
|
||||
# Empty last line
|
||||
|
||||
INCLUDES= -I .. -I ../$(CPROVER_DIR)/src
|
||||
|
|
|
@ -0,0 +1,303 @@
|
|||
/*******************************************************************\
|
||||
|
||||
Module: Symbolic Execution of ANSI-C
|
||||
|
||||
Author: Daniel Kroening, kroening@kroening.com
|
||||
|
||||
\*******************************************************************/
|
||||
|
||||
/// \file
|
||||
/// Symbolic Execution of ANSI-C
|
||||
|
||||
#include "all_properties_class.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
|
||||
#include <goto-checker/bmc_util.h>
|
||||
#include <goto-checker/report_util.h>
|
||||
|
||||
#include <util/json.h>
|
||||
#include <util/xml.h>
|
||||
|
||||
#include <solvers/prop/prop_conv.h>
|
||||
#include <solvers/sat/satcheck.h>
|
||||
|
||||
#include <goto-programs/json_goto_trace.h>
|
||||
#include <goto-programs/xml_goto_trace.h>
|
||||
#include <goto-symex/build_goto_trace.h>
|
||||
|
||||
void bmc_all_propertiest::goal_covered(const cover_goalst::goalt &)
|
||||
{
|
||||
for(auto &g : goal_map)
|
||||
{
|
||||
// failed already?
|
||||
if(g.second.status == goalt::statust::FAILURE)
|
||||
continue;
|
||||
|
||||
// check whether failed
|
||||
for(auto &c : g.second.instances)
|
||||
{
|
||||
literalt cond = c->cond_literal;
|
||||
|
||||
if(solver.l_get(cond).is_false())
|
||||
{
|
||||
g.second.status = goalt::statust::FAILURE;
|
||||
build_goto_trace(bmc.equation, c, solver, bmc.ns, g.second.goto_trace);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
safety_checkert::resultt bmc_all_propertiest::operator()()
|
||||
{
|
||||
status() << "Passing problem to " << solver.decision_procedure_text() << eom;
|
||||
|
||||
auto solver_start = std::chrono::steady_clock::now();
|
||||
|
||||
convert_symex_target_equation(
|
||||
bmc.equation, bmc.prop_conv, get_message_handler());
|
||||
bmc.freeze_program_variables();
|
||||
|
||||
// Collect _all_ goals in `goal_map'.
|
||||
// This maps property IDs to 'goalt'
|
||||
forall_goto_functions(f_it, goto_functions)
|
||||
forall_goto_program_instructions(i_it, f_it->second.body)
|
||||
if(i_it->is_assert())
|
||||
goal_map[i_it->source_location.get_property_id()] = goalt(*i_it);
|
||||
|
||||
// get the conditions for these goals from formula
|
||||
// collect all 'instances' of the properties
|
||||
for(symex_target_equationt::SSA_stepst::iterator it =
|
||||
bmc.equation.SSA_steps.begin();
|
||||
it != bmc.equation.SSA_steps.end();
|
||||
it++)
|
||||
{
|
||||
if(it->is_assert())
|
||||
{
|
||||
irep_idt property_id = it->get_property_id();
|
||||
|
||||
if(property_id.empty())
|
||||
continue;
|
||||
|
||||
if(it->source.pc->is_goto())
|
||||
{
|
||||
// goto may yield an unwinding assertion
|
||||
goal_map[property_id].description = it->comment;
|
||||
}
|
||||
|
||||
goal_map[property_id].instances.push_back(it);
|
||||
}
|
||||
}
|
||||
|
||||
do_before_solving();
|
||||
|
||||
cover_goalst cover_goals(solver);
|
||||
|
||||
cover_goals.register_observer(*this);
|
||||
|
||||
for(const auto &g : goal_map)
|
||||
{
|
||||
// Our goal is to falsify a property, i.e., we will
|
||||
// add the negation of the property as goal.
|
||||
literalt p = !solver.convert(g.second.as_expr());
|
||||
cover_goals.add(p);
|
||||
}
|
||||
|
||||
status() << "Running " << solver.decision_procedure_text() << eom;
|
||||
|
||||
bool error = false;
|
||||
|
||||
const decision_proceduret::resultt result =
|
||||
cover_goals(get_message_handler());
|
||||
|
||||
if(result == decision_proceduret::resultt::D_ERROR)
|
||||
{
|
||||
error = true;
|
||||
for(auto &g : goal_map)
|
||||
if(g.second.status == goalt::statust::UNKNOWN)
|
||||
g.second.status = goalt::statust::ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
for(auto &g : goal_map)
|
||||
if(g.second.status == goalt::statust::UNKNOWN)
|
||||
g.second.status = goalt::statust::SUCCESS;
|
||||
}
|
||||
|
||||
{
|
||||
auto solver_stop = std::chrono::steady_clock::now();
|
||||
|
||||
statistics()
|
||||
<< "Runtime decision procedure: "
|
||||
<< std::chrono::duration<double>(solver_stop - solver_start).count()
|
||||
<< "s" << eom;
|
||||
}
|
||||
|
||||
// report
|
||||
report(cover_goals);
|
||||
|
||||
if(error)
|
||||
return safety_checkert::resultt::ERROR;
|
||||
|
||||
bool safe = (cover_goals.number_covered() == 0);
|
||||
|
||||
if(safe)
|
||||
report_success(bmc.ui_message_handler); // legacy, might go away
|
||||
else
|
||||
report_failure(bmc.ui_message_handler); // legacy, might go away
|
||||
|
||||
return safe ? safety_checkert::resultt::SAFE
|
||||
: safety_checkert::resultt::UNSAFE;
|
||||
}
|
||||
|
||||
void bmc_all_propertiest::report(const cover_goalst &cover_goals)
|
||||
{
|
||||
switch(bmc.ui_message_handler.get_ui())
|
||||
{
|
||||
case ui_message_handlert::uit::PLAIN:
|
||||
{
|
||||
result() << "\n** Results:" << eom;
|
||||
|
||||
// collect goals in a vector
|
||||
std::vector<goal_mapt::const_iterator> goals;
|
||||
|
||||
for(auto g_it = goal_map.begin(); g_it != goal_map.end(); g_it++)
|
||||
goals.push_back(g_it);
|
||||
|
||||
// now determine an ordering for those goals:
|
||||
// 1. alphabetical ordering of file name
|
||||
// 2. numerical ordering of line number
|
||||
// 3. alphabetical ordering of goal ID
|
||||
std::sort(
|
||||
goals.begin(),
|
||||
goals.end(),
|
||||
[](goal_mapt::const_iterator git1, goal_mapt::const_iterator git2) {
|
||||
const auto &g1 = git1->second.source_location;
|
||||
const auto &g2 = git2->second.source_location;
|
||||
if(g1.get_file() != g2.get_file())
|
||||
return id2string(g1.get_file()) < id2string(g2.get_file());
|
||||
else if(!g1.get_line().empty() && !g2.get_line().empty())
|
||||
return std::stoul(id2string(g1.get_line())) <
|
||||
std::stoul(id2string(g2.get_line()));
|
||||
else
|
||||
return id2string(git1->first) < id2string(git2->first);
|
||||
});
|
||||
|
||||
// now show in the order we have determined
|
||||
|
||||
irep_idt previous_function;
|
||||
irep_idt current_file;
|
||||
for(const auto &g : goals)
|
||||
{
|
||||
const auto &l = g->second.source_location;
|
||||
|
||||
if(l.get_function() != previous_function)
|
||||
{
|
||||
if(!previous_function.empty())
|
||||
result() << '\n';
|
||||
previous_function = l.get_function();
|
||||
if(!previous_function.empty())
|
||||
{
|
||||
current_file = l.get_file();
|
||||
if(!current_file.empty())
|
||||
result() << current_file << ' ';
|
||||
if(!l.get_function().empty())
|
||||
result() << "function " << l.get_function();
|
||||
result() << eom;
|
||||
}
|
||||
}
|
||||
|
||||
result() << faint << '[' << g->first << "] " << reset;
|
||||
|
||||
if(l.get_file() != current_file)
|
||||
result() << "file " << l.get_file() << ' ';
|
||||
|
||||
if(!l.get_line().empty())
|
||||
result() << "line " << l.get_line() << ' ';
|
||||
|
||||
result() << g->second.description << ": ";
|
||||
|
||||
if(g->second.status == goalt::statust::SUCCESS)
|
||||
result() << green;
|
||||
else
|
||||
result() << red;
|
||||
|
||||
result() << g->second.status_string() << reset << eom;
|
||||
}
|
||||
|
||||
if(bmc.options.get_bool_option("trace"))
|
||||
{
|
||||
for(const auto &g : goal_map)
|
||||
if(g.second.status == goalt::statust::FAILURE)
|
||||
{
|
||||
result() << "\n"
|
||||
<< "Trace for " << g.first << ":"
|
||||
<< "\n";
|
||||
show_goto_trace(
|
||||
result(), bmc.ns, g.second.goto_trace, bmc.trace_options());
|
||||
result() << eom;
|
||||
}
|
||||
}
|
||||
|
||||
status() << "\n** " << cover_goals.number_covered() << " of "
|
||||
<< cover_goals.size() << " failed (" << cover_goals.iterations()
|
||||
<< " iteration" << (cover_goals.iterations() == 1 ? "" : "s")
|
||||
<< ")" << eom;
|
||||
}
|
||||
break;
|
||||
|
||||
case ui_message_handlert::uit::XML_UI:
|
||||
{
|
||||
for(const auto &g : goal_map)
|
||||
{
|
||||
xmlt xml_result(
|
||||
"result",
|
||||
{{"property", id2string(g.first)},
|
||||
{"status", g.second.status_string()}},
|
||||
{});
|
||||
|
||||
if(g.second.status == goalt::statust::FAILURE)
|
||||
convert(bmc.ns, g.second.goto_trace, xml_result.new_element());
|
||||
|
||||
result() << xml_result;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ui_message_handlert::uit::JSON_UI:
|
||||
{
|
||||
if(result().tellp() > 0)
|
||||
result() << eom; // force end of previous message
|
||||
json_stream_objectt &json_result =
|
||||
bmc.ui_message_handler.get_json_stream().push_back_stream_object();
|
||||
json_stream_arrayt &result_array =
|
||||
json_result.push_back_stream_array("result");
|
||||
|
||||
for(const auto &g : goal_map)
|
||||
{
|
||||
json_stream_objectt &result = result_array.push_back_stream_object();
|
||||
result["property"] = json_stringt(g.first);
|
||||
result["description"] = json_stringt(g.second.description);
|
||||
result["status"] = json_stringt(g.second.status_string());
|
||||
|
||||
if(g.second.status == goalt::statust::FAILURE)
|
||||
{
|
||||
json_stream_arrayt &json_trace = result.push_back_stream_array("trace");
|
||||
convert<json_stream_arrayt>(
|
||||
bmc.ns, g.second.goto_trace, json_trace, bmc.trace_options());
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
safety_checkert::resultt
|
||||
bmct::all_properties(const goto_functionst &goto_functions)
|
||||
{
|
||||
bmc_all_propertiest bmc_all_properties(goto_functions, prop_conv, *this);
|
||||
bmc_all_properties.set_message_handler(get_message_handler());
|
||||
return bmc_all_properties();
|
||||
}
|
|
@ -17,16 +17,14 @@ Author: Daniel Kroening, kroening@kroening.com
|
|||
|
||||
#include "bmc.h"
|
||||
|
||||
class bmc_all_propertiest:
|
||||
public cover_goalst::observert,
|
||||
public messaget
|
||||
class bmc_all_propertiest : public cover_goalst::observert, public messaget
|
||||
{
|
||||
public:
|
||||
bmc_all_propertiest(
|
||||
const goto_functionst &_goto_functions,
|
||||
prop_convt &_solver,
|
||||
bmct &_bmc):
|
||||
goto_functions(_goto_functions), solver(_solver), bmc(_bmc)
|
||||
bmct &_bmc)
|
||||
: goto_functions(_goto_functions), solver(_solver), bmc(_bmc)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -44,17 +42,27 @@ public:
|
|||
source_locationt source_location;
|
||||
|
||||
// if failed, we compute a goto_trace for the first failing instance
|
||||
enum statust { UNKNOWN, FAILURE, SUCCESS, ERROR } status;
|
||||
enum statust
|
||||
{
|
||||
UNKNOWN,
|
||||
FAILURE,
|
||||
SUCCESS,
|
||||
ERROR
|
||||
} status;
|
||||
goto_tracet goto_trace;
|
||||
|
||||
std::string status_string() const
|
||||
{
|
||||
switch(status)
|
||||
{
|
||||
case UNKNOWN: return "UNKNOWN";
|
||||
case FAILURE: return "FAILURE";
|
||||
case SUCCESS: return "SUCCESS";
|
||||
case ERROR: return "ERROR";
|
||||
case UNKNOWN:
|
||||
return "UNKNOWN";
|
||||
case FAILURE:
|
||||
return "FAILURE";
|
||||
case SUCCESS:
|
||||
return "SUCCESS";
|
||||
case ERROR:
|
||||
return "ERROR";
|
||||
}
|
||||
|
||||
// make some poor compilers happy
|
||||
|
@ -62,15 +70,14 @@ public:
|
|||
return "";
|
||||
}
|
||||
|
||||
explicit goalt(
|
||||
const goto_programt::instructiont &instruction):
|
||||
status(statust::UNKNOWN)
|
||||
explicit goalt(const goto_programt::instructiont &instruction)
|
||||
: status(statust::UNKNOWN)
|
||||
{
|
||||
source_location = instruction.source_location;
|
||||
description=id2string(instruction.source_location.get_comment());
|
||||
description = id2string(instruction.source_location.get_comment());
|
||||
}
|
||||
|
||||
goalt():status(statust::UNKNOWN)
|
||||
goalt() : status(statust::UNKNOWN)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -93,7 +100,9 @@ protected:
|
|||
bmct &bmc;
|
||||
|
||||
virtual void report(const cover_goalst &cover_goals);
|
||||
virtual void do_before_solving() {}
|
||||
virtual void do_before_solving()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
#endif // CPROVER_CBMC_ALL_PROPERTIES_CLASS_H
|
|
@ -42,8 +42,8 @@ void bmct::freeze_program_variables()
|
|||
|
||||
decision_proceduret::resultt bmct::run_decision_procedure()
|
||||
{
|
||||
status() << "Passing problem to "
|
||||
<< prop_conv.decision_procedure_text() << eom;
|
||||
status() << "Passing problem to " << prop_conv.decision_procedure_text()
|
||||
<< eom;
|
||||
|
||||
auto solver_start = std::chrono::steady_clock::now();
|
||||
|
||||
|
@ -54,7 +54,7 @@ decision_proceduret::resultt bmct::run_decision_procedure()
|
|||
|
||||
status() << "Running " << prop_conv.decision_procedure_text() << eom;
|
||||
|
||||
decision_proceduret::resultt dec_result=prop_conv.dec_solve();
|
||||
decision_proceduret::resultt dec_result = prop_conv.dec_solve();
|
||||
|
||||
{
|
||||
auto solver_stop = std::chrono::steady_clock::now();
|
||||
|
@ -67,14 +67,13 @@ decision_proceduret::resultt bmct::run_decision_procedure()
|
|||
return dec_result;
|
||||
}
|
||||
|
||||
safety_checkert::resultt bmct::execute(
|
||||
abstract_goto_modelt &goto_model)
|
||||
safety_checkert::resultt bmct::execute(abstract_goto_modelt &goto_model)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto get_goto_function = [&goto_model](const irep_idt &id) ->
|
||||
const goto_functionst::goto_functiont &
|
||||
{
|
||||
auto get_goto_function =
|
||||
[&goto_model](
|
||||
const irep_idt &id) -> const goto_functionst::goto_functiont & {
|
||||
return goto_model.get_goto_function(id);
|
||||
};
|
||||
|
||||
|
@ -84,8 +83,7 @@ safety_checkert::resultt bmct::execute(
|
|||
// iterators pointing into it, must not be stored by this function or its
|
||||
// callees, as goto_model.get_goto_function (as used by symex)
|
||||
// will have side-effects on it.
|
||||
const goto_functionst &goto_functions =
|
||||
goto_model.get_goto_functions();
|
||||
const goto_functionst &goto_functions = goto_model.get_goto_functions();
|
||||
|
||||
// This provides the driver program the opportunity to do things like a
|
||||
// symbol-table or goto-functions dump instead of actually running the
|
||||
|
@ -108,16 +106,15 @@ safety_checkert::resultt bmct::execute(
|
|||
(*memory_model)(equation);
|
||||
}
|
||||
|
||||
statistics() << "size of program expression: "
|
||||
<< equation.SSA_steps.size()
|
||||
statistics() << "size of program expression: " << equation.SSA_steps.size()
|
||||
<< " steps" << eom;
|
||||
|
||||
slice(symex, equation, ns, options, ui_message_handler);
|
||||
|
||||
// coverage report
|
||||
std::string cov_out=options.get_option("symex-coverage-report");
|
||||
if(!cov_out.empty() &&
|
||||
symex.output_coverage_report(goto_functions, cov_out))
|
||||
std::string cov_out = options.get_option("symex-coverage-report");
|
||||
if(
|
||||
!cov_out.empty() && symex.output_coverage_report(goto_functions, cov_out))
|
||||
{
|
||||
error() << "Failed to write symex coverage report" << eom;
|
||||
return safety_checkert::resultt::ERROR;
|
||||
|
@ -156,7 +153,7 @@ safety_checkert::resultt bmct::execute(
|
|||
catch(const std::string &error_str)
|
||||
{
|
||||
messaget message(get_message_handler());
|
||||
message.error().source_location=symex.last_source_location;
|
||||
message.error().source_location = symex.last_source_location;
|
||||
message.error() << error_str << messaget::eom;
|
||||
|
||||
return safety_checkert::resultt::ERROR;
|
||||
|
@ -165,7 +162,7 @@ safety_checkert::resultt bmct::execute(
|
|||
catch(const char *error_str)
|
||||
{
|
||||
messaget message(get_message_handler());
|
||||
message.error().source_location=symex.last_source_location;
|
||||
message.error().source_location = symex.last_source_location;
|
||||
message.error() << error_str << messaget::eom;
|
||||
|
||||
return safety_checkert::resultt::ERROR;
|
||||
|
@ -178,9 +175,7 @@ safety_checkert::resultt bmct::execute(
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
safety_checkert::resultt bmct::run(
|
||||
abstract_goto_modelt &goto_model)
|
||||
safety_checkert::resultt bmct::run(abstract_goto_modelt &goto_model)
|
||||
{
|
||||
memory_model = get_memory_model(options, ns);
|
||||
setup_symex(symex, ns, options, ui_message_handler);
|
||||
|
@ -222,8 +217,7 @@ safety_checkert::resultt bmct::stop_on_fail()
|
|||
return resultt::UNSAFE;
|
||||
|
||||
default:
|
||||
if(options.get_bool_option("dimacs") ||
|
||||
options.get_option("outfile")!="")
|
||||
if(options.get_bool_option("dimacs") || options.get_option("outfile") != "")
|
||||
return resultt::SAFE;
|
||||
|
||||
error() << "decision procedure failed" << eom;
|
|
@ -15,23 +15,22 @@ Author: Daniel Kroening, kroening@kroening.com
|
|||
#include <list>
|
||||
#include <map>
|
||||
|
||||
#include <util/decision_procedure.h>
|
||||
#include <util/invariant.h>
|
||||
#include <util/options.h>
|
||||
#include <util/ui_message.h>
|
||||
#include <util/decision_procedure.h>
|
||||
|
||||
#include <goto-checker/symex_bmc.h>
|
||||
|
||||
#include <goto-programs/goto_trace.h>
|
||||
|
||||
#include <goto-symex/symex_target_equation.h>
|
||||
#include <goto-symex/path_storage.h>
|
||||
#include <goto-symex/symex_target_equation.h>
|
||||
|
||||
#include <goto-programs/goto_model.h>
|
||||
#include <goto-programs/safety_checker.h>
|
||||
#include <goto-symex/memory_model.h>
|
||||
|
||||
|
||||
class cbmc_solverst;
|
||||
|
||||
/// \brief Bounded model checking or path exploration for goto-programs
|
||||
|
@ -39,7 +38,7 @@ class cbmc_solverst;
|
|||
/// Higher-level architectural information on symbolic execution is
|
||||
/// documented in the \ref symex-overview
|
||||
/// "Symbolic execution module page".
|
||||
class bmct:public safety_checkert
|
||||
class bmct : public safety_checkert
|
||||
{
|
||||
public:
|
||||
/// \brief Constructor for path exploration with freshly-initialized state
|
||||
|
@ -100,11 +99,12 @@ public:
|
|||
resultt run(abstract_goto_modelt &);
|
||||
void setup();
|
||||
safety_checkert::resultt execute(abstract_goto_modelt &);
|
||||
virtual ~bmct() { }
|
||||
virtual ~bmct()
|
||||
{
|
||||
}
|
||||
|
||||
// the safety_checkert interface
|
||||
virtual resultt operator()(
|
||||
const goto_functionst &goto_functions)
|
||||
virtual resultt operator()(const goto_functionst &goto_functions)
|
||||
{
|
||||
return run(goto_functions);
|
||||
}
|
||||
|
@ -114,8 +114,8 @@ public:
|
|||
symex.add_loop_unwind_handler(handler);
|
||||
}
|
||||
|
||||
void add_unwind_recursion_handler(
|
||||
symex_bmct::recursion_unwind_handlert handler)
|
||||
void
|
||||
add_unwind_recursion_handler(symex_bmct::recursion_unwind_handlert handler)
|
||||
{
|
||||
symex.add_recursion_unwind_handler(handler);
|
||||
}
|
||||
|
@ -207,8 +207,8 @@ private:
|
|||
/// invoke the symbolic executor in a class-specific way. This
|
||||
/// implementation invokes goto_symext::operator() to perform
|
||||
/// full-program model-checking from the entry point of the program.
|
||||
virtual void perform_symbolic_execution(
|
||||
goto_symext::get_goto_functiont get_goto_function);
|
||||
virtual void
|
||||
perform_symbolic_execution(goto_symext::get_goto_functiont get_goto_function);
|
||||
|
||||
/// Optional callback, to be run after symex but before handing the resulting
|
||||
/// equation to the solver. If it returns true then we will skip the solver
|
|
@ -61,7 +61,7 @@ Author: Daniel Kroening, kroening@kroening.com
|
|||
|
||||
#include <langapi/mode.h>
|
||||
|
||||
#include <cbmc/bmc.h> // will go away
|
||||
#include "bmc.h" // will go away
|
||||
|
||||
#include <java_bytecode/convert_java_nondet.h>
|
||||
#include <java_bytecode/java_bytecode_language.h>
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
analyses
|
||||
ansi-c # should go away
|
||||
cbmc # bmc.h - will go away
|
||||
goto-checker
|
||||
goto-instrument
|
||||
goto-programs
|
||||
|
@ -11,5 +10,7 @@ langapi # should go away
|
|||
linking
|
||||
pointer-analysis
|
||||
solvers/refinement
|
||||
solvers/prop
|
||||
solvers/sat
|
||||
solvers/strings
|
||||
util
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
SRC = all_properties.cpp \
|
||||
bmc.cpp \
|
||||
c_test_input_generator.cpp \
|
||||
SRC = c_test_input_generator.cpp \
|
||||
cbmc_languages.cpp \
|
||||
cbmc_main.cpp \
|
||||
cbmc_parse_options.cpp \
|
||||
|
|
|
@ -1,302 +0,0 @@
|
|||
/*******************************************************************\
|
||||
|
||||
Module: Symbolic Execution of ANSI-C
|
||||
|
||||
Author: Daniel Kroening, kroening@kroening.com
|
||||
|
||||
\*******************************************************************/
|
||||
|
||||
/// \file
|
||||
/// Symbolic Execution of ANSI-C
|
||||
|
||||
#include "all_properties_class.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
|
||||
#include <goto-checker/bmc_util.h>
|
||||
#include <goto-checker/report_util.h>
|
||||
|
||||
#include <util/xml.h>
|
||||
#include <util/json.h>
|
||||
|
||||
#include <solvers/prop/prop_conv.h>
|
||||
#include <solvers/sat/satcheck.h>
|
||||
|
||||
#include <goto-symex/build_goto_trace.h>
|
||||
#include <goto-programs/xml_goto_trace.h>
|
||||
#include <goto-programs/json_goto_trace.h>
|
||||
|
||||
void bmc_all_propertiest::goal_covered(const cover_goalst::goalt &)
|
||||
{
|
||||
for(auto &g : goal_map)
|
||||
{
|
||||
// failed already?
|
||||
if(g.second.status==goalt::statust::FAILURE)
|
||||
continue;
|
||||
|
||||
// check whether failed
|
||||
for(auto &c : g.second.instances)
|
||||
{
|
||||
literalt cond=c->cond_literal;
|
||||
|
||||
if(solver.l_get(cond).is_false())
|
||||
{
|
||||
g.second.status=goalt::statust::FAILURE;
|
||||
build_goto_trace(bmc.equation, c, solver, bmc.ns, g.second.goto_trace);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
safety_checkert::resultt bmc_all_propertiest::operator()()
|
||||
{
|
||||
status() << "Passing problem to " << solver.decision_procedure_text() << eom;
|
||||
|
||||
auto solver_start=std::chrono::steady_clock::now();
|
||||
|
||||
convert_symex_target_equation(
|
||||
bmc.equation, bmc.prop_conv, get_message_handler());
|
||||
bmc.freeze_program_variables();
|
||||
|
||||
// Collect _all_ goals in `goal_map'.
|
||||
// This maps property IDs to 'goalt'
|
||||
forall_goto_functions(f_it, goto_functions)
|
||||
forall_goto_program_instructions(i_it, f_it->second.body)
|
||||
if(i_it->is_assert())
|
||||
goal_map[i_it->source_location.get_property_id()]=goalt(*i_it);
|
||||
|
||||
// get the conditions for these goals from formula
|
||||
// collect all 'instances' of the properties
|
||||
for(symex_target_equationt::SSA_stepst::iterator
|
||||
it=bmc.equation.SSA_steps.begin();
|
||||
it!=bmc.equation.SSA_steps.end();
|
||||
it++)
|
||||
{
|
||||
if(it->is_assert())
|
||||
{
|
||||
irep_idt property_id = it->get_property_id();
|
||||
|
||||
if(property_id.empty())
|
||||
continue;
|
||||
|
||||
if(it->source.pc->is_goto())
|
||||
{
|
||||
// goto may yield an unwinding assertion
|
||||
goal_map[property_id].description = it->comment;
|
||||
}
|
||||
|
||||
goal_map[property_id].instances.push_back(it);
|
||||
}
|
||||
}
|
||||
|
||||
do_before_solving();
|
||||
|
||||
cover_goalst cover_goals(solver);
|
||||
|
||||
cover_goals.register_observer(*this);
|
||||
|
||||
for(const auto &g : goal_map)
|
||||
{
|
||||
// Our goal is to falsify a property, i.e., we will
|
||||
// add the negation of the property as goal.
|
||||
literalt p=!solver.convert(g.second.as_expr());
|
||||
cover_goals.add(p);
|
||||
}
|
||||
|
||||
status() << "Running " << solver.decision_procedure_text() << eom;
|
||||
|
||||
bool error=false;
|
||||
|
||||
const decision_proceduret::resultt result =
|
||||
cover_goals(get_message_handler());
|
||||
|
||||
if(result==decision_proceduret::resultt::D_ERROR)
|
||||
{
|
||||
error=true;
|
||||
for(auto &g : goal_map)
|
||||
if(g.second.status==goalt::statust::UNKNOWN)
|
||||
g.second.status=goalt::statust::ERROR;
|
||||
}
|
||||
else
|
||||
{
|
||||
for(auto &g : goal_map)
|
||||
if(g.second.status==goalt::statust::UNKNOWN)
|
||||
g.second.status=goalt::statust::SUCCESS;
|
||||
}
|
||||
|
||||
{
|
||||
auto solver_stop = std::chrono::steady_clock::now();
|
||||
|
||||
statistics()
|
||||
<< "Runtime decision procedure: "
|
||||
<< std::chrono::duration<double>(solver_stop - solver_start).count()
|
||||
<< "s" << eom;
|
||||
}
|
||||
|
||||
// report
|
||||
report(cover_goals);
|
||||
|
||||
if(error)
|
||||
return safety_checkert::resultt::ERROR;
|
||||
|
||||
bool safe=(cover_goals.number_covered()==0);
|
||||
|
||||
if(safe)
|
||||
report_success(bmc.ui_message_handler); // legacy, might go away
|
||||
else
|
||||
report_failure(bmc.ui_message_handler); // legacy, might go away
|
||||
|
||||
return safe?safety_checkert::resultt::SAFE:safety_checkert::resultt::UNSAFE;
|
||||
}
|
||||
|
||||
void bmc_all_propertiest::report(const cover_goalst &cover_goals)
|
||||
{
|
||||
switch(bmc.ui_message_handler.get_ui())
|
||||
{
|
||||
case ui_message_handlert::uit::PLAIN:
|
||||
{
|
||||
result() << "\n** Results:" << eom;
|
||||
|
||||
// collect goals in a vector
|
||||
std::vector<goal_mapt::const_iterator> goals;
|
||||
|
||||
for(auto g_it = goal_map.begin(); g_it != goal_map.end(); g_it++)
|
||||
goals.push_back(g_it);
|
||||
|
||||
// now determine an ordering for those goals:
|
||||
// 1. alphabetical ordering of file name
|
||||
// 2. numerical ordering of line number
|
||||
// 3. alphabetical ordering of goal ID
|
||||
std::sort(
|
||||
goals.begin(),
|
||||
goals.end(),
|
||||
[](goal_mapt::const_iterator git1, goal_mapt::const_iterator git2) {
|
||||
const auto &g1 = git1->second.source_location;
|
||||
const auto &g2 = git2->second.source_location;
|
||||
if(g1.get_file() != g2.get_file())
|
||||
return id2string(g1.get_file()) < id2string(g2.get_file());
|
||||
else if(!g1.get_line().empty() && !g2.get_line().empty())
|
||||
return std::stoul(id2string(g1.get_line())) <
|
||||
std::stoul(id2string(g2.get_line()));
|
||||
else
|
||||
return id2string(git1->first) < id2string(git2->first);
|
||||
});
|
||||
|
||||
// now show in the order we have determined
|
||||
|
||||
irep_idt previous_function;
|
||||
irep_idt current_file;
|
||||
for(const auto &g : goals)
|
||||
{
|
||||
const auto &l = g->second.source_location;
|
||||
|
||||
if(l.get_function() != previous_function)
|
||||
{
|
||||
if(!previous_function.empty())
|
||||
result() << '\n';
|
||||
previous_function = l.get_function();
|
||||
if(!previous_function.empty())
|
||||
{
|
||||
current_file = l.get_file();
|
||||
if(!current_file.empty())
|
||||
result() << current_file << ' ';
|
||||
if(!l.get_function().empty())
|
||||
result() << "function " << l.get_function();
|
||||
result() << eom;
|
||||
}
|
||||
}
|
||||
|
||||
result() << faint << '[' << g->first << "] " << reset;
|
||||
|
||||
if(l.get_file() != current_file)
|
||||
result() << "file " << l.get_file() << ' ';
|
||||
|
||||
if(!l.get_line().empty())
|
||||
result() << "line " << l.get_line() << ' ';
|
||||
|
||||
result() << g->second.description << ": ";
|
||||
|
||||
if(g->second.status == goalt::statust::SUCCESS)
|
||||
result() << green;
|
||||
else
|
||||
result() << red;
|
||||
|
||||
result() << g->second.status_string() << reset << eom;
|
||||
}
|
||||
|
||||
if(bmc.options.get_bool_option("trace"))
|
||||
{
|
||||
for(const auto &g : goal_map)
|
||||
if(g.second.status==goalt::statust::FAILURE)
|
||||
{
|
||||
result() << "\n" << "Trace for " << g.first << ":" << "\n";
|
||||
show_goto_trace(
|
||||
result(), bmc.ns, g.second.goto_trace, bmc.trace_options());
|
||||
result() << eom;
|
||||
}
|
||||
}
|
||||
|
||||
status() << "\n** " << cover_goals.number_covered()
|
||||
<< " of " << cover_goals.size() << " failed ("
|
||||
<< cover_goals.iterations() << " iteration"
|
||||
<< (cover_goals.iterations()==1?"":"s")
|
||||
<< ")" << eom;
|
||||
}
|
||||
break;
|
||||
|
||||
case ui_message_handlert::uit::XML_UI:
|
||||
{
|
||||
for(const auto &g : goal_map)
|
||||
{
|
||||
xmlt xml_result(
|
||||
"result",
|
||||
{{"property", id2string(g.first)},
|
||||
{"status", g.second.status_string()}},
|
||||
{});
|
||||
|
||||
if(g.second.status==goalt::statust::FAILURE)
|
||||
convert(bmc.ns, g.second.goto_trace, xml_result.new_element());
|
||||
|
||||
result() << xml_result;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ui_message_handlert::uit::JSON_UI:
|
||||
{
|
||||
if(result().tellp() > 0)
|
||||
result() << eom; // force end of previous message
|
||||
json_stream_objectt &json_result =
|
||||
bmc.ui_message_handler.get_json_stream().push_back_stream_object();
|
||||
json_stream_arrayt &result_array =
|
||||
json_result.push_back_stream_array("result");
|
||||
|
||||
for(const auto &g : goal_map)
|
||||
{
|
||||
json_stream_objectt &result = result_array.push_back_stream_object();
|
||||
result["property"] = json_stringt(g.first);
|
||||
result["description"] = json_stringt(g.second.description);
|
||||
result["status"]=json_stringt(g.second.status_string());
|
||||
|
||||
if(g.second.status==goalt::statust::FAILURE)
|
||||
{
|
||||
json_stream_arrayt &json_trace =
|
||||
result.push_back_stream_array("trace");
|
||||
convert<json_stream_arrayt>(
|
||||
bmc.ns, g.second.goto_trace, json_trace, bmc.trace_options());
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
safety_checkert::resultt
|
||||
bmct::all_properties(const goto_functionst &goto_functions)
|
||||
{
|
||||
bmc_all_propertiest bmc_all_properties(goto_functions, prop_conv, *this);
|
||||
bmc_all_properties.set_message_handler(get_message_handler());
|
||||
return bmc_all_properties();
|
||||
}
|
|
@ -31,7 +31,6 @@ Author: Daniel Kroening, kroening@kroening.com
|
|||
|
||||
#include <solvers/strings/string_refinement.h>
|
||||
|
||||
#include "bmc.h"
|
||||
#include "xml_interface.h"
|
||||
|
||||
class goto_functionst;
|
||||
|
|
|
@ -99,9 +99,7 @@ testing-utils-clean:
|
|||
$(MAKE) $(MAKEARGS) -C testing-utils clean
|
||||
|
||||
# We need to link bmc.o to the unit test, so here's everything it depends on...
|
||||
BMC_DEPS =../src/cbmc/all_properties$(OBJEXT) \
|
||||
../src/cbmc/bmc$(OBJEXT) \
|
||||
../src/cbmc/c_test_input_generator$(OBJEXT) \
|
||||
BMC_DEPS =../src/cbmc/c_test_input_generator$(OBJEXT) \
|
||||
../src/cbmc/cbmc_languages$(OBJEXT) \
|
||||
../src/cbmc/cbmc_parse_options$(OBJEXT) \
|
||||
../src/cbmc/xml_interface$(OBJEXT) \
|
||||
|
|
|
@ -16,10 +16,11 @@ Author: Kareem Khazem <karkhaz@karkhaz.com>, 2018
|
|||
|
||||
#include <ansi-c/ansi_c_language.h>
|
||||
|
||||
#include <cbmc/bmc.h>
|
||||
#include <cbmc/cbmc_parse_options.h>
|
||||
|
||||
#include <goto-checker/solver_factory.h>
|
||||
#include <goto-checker/bmc_util.h>
|
||||
#include <goto-checker/goto_symex_property_decider.h>
|
||||
#include <goto-checker/symex_bmc.h>
|
||||
|
||||
#include <langapi/mode.h>
|
||||
|
||||
|
@ -42,8 +43,8 @@ Author: Kareem Khazem <karkhaz@karkhaz.com>, 2018
|
|||
// `goto` instruction.
|
||||
//
|
||||
// Whenever symbolic execution reaches the end of a path, you should expect a
|
||||
// result. Results are either SUCCESS, meaning that verification of that path
|
||||
// succeeded, or FAILURE, meaning that there was an assertion failure on that
|
||||
// result. Results are either DONE, meaning that verification of that path
|
||||
// succeeded, or FOUND_FAIL, meaning that there was an assertion failure on that
|
||||
// path.
|
||||
//
|
||||
// To figure out what the events should be, run CBMC on the test program with
|
||||
|
@ -80,14 +81,18 @@ SCENARIO("path strategies")
|
|||
"lifo",
|
||||
opts_callback,
|
||||
c,
|
||||
{symex_eventt::resume(symex_eventt::enumt::JUMP, 7),
|
||||
{// Entry state is line 0
|
||||
symex_eventt::resume(symex_eventt::enumt::NEXT, 0),
|
||||
symex_eventt::resume(symex_eventt::enumt::JUMP, 7),
|
||||
symex_eventt::resume(symex_eventt::enumt::NEXT, 5),
|
||||
symex_eventt::result(symex_eventt::enumt::SUCCESS)});
|
||||
check_with_strategy(
|
||||
"fifo",
|
||||
opts_callback,
|
||||
c,
|
||||
{symex_eventt::resume(symex_eventt::enumt::NEXT, 5),
|
||||
{// Entry state is line 0
|
||||
symex_eventt::resume(symex_eventt::enumt::NEXT, 0),
|
||||
symex_eventt::resume(symex_eventt::enumt::NEXT, 5),
|
||||
symex_eventt::resume(symex_eventt::enumt::JUMP, 7),
|
||||
symex_eventt::result(symex_eventt::enumt::SUCCESS)});
|
||||
}
|
||||
|
@ -120,7 +125,9 @@ SCENARIO("path strategies")
|
|||
"lifo",
|
||||
opts_callback,
|
||||
c,
|
||||
{// Outer else, inner else
|
||||
{// Entry state is line 0
|
||||
symex_eventt::resume(symex_eventt::enumt::NEXT, 0),
|
||||
// Outer else, inner else
|
||||
symex_eventt::resume(symex_eventt::enumt::JUMP, 13),
|
||||
symex_eventt::resume(symex_eventt::enumt::JUMP, 16),
|
||||
// Outer else, inner if
|
||||
|
@ -136,7 +143,9 @@ SCENARIO("path strategies")
|
|||
"fifo",
|
||||
opts_callback,
|
||||
c,
|
||||
{// Expand outer if, but don't continue depth-first
|
||||
{// Entry state is line 0
|
||||
symex_eventt::resume(symex_eventt::enumt::NEXT, 0),
|
||||
// Expand outer if, but don't continue depth-first
|
||||
symex_eventt::resume(symex_eventt::enumt::NEXT, 6),
|
||||
// Jump to outer else, but again don't continue depth-first
|
||||
symex_eventt::resume(symex_eventt::enumt::JUMP, 13),
|
||||
|
@ -175,6 +184,9 @@ SCENARIO("path strategies")
|
|||
opts_callback,
|
||||
c,
|
||||
{
|
||||
// Entry state is line 0
|
||||
symex_eventt::resume(symex_eventt::enumt::NEXT, 0),
|
||||
|
||||
// The path where x != 1 and we have nothing to check:
|
||||
symex_eventt::resume(symex_eventt::enumt::JUMP, 11),
|
||||
|
||||
|
@ -204,6 +216,9 @@ SCENARIO("path strategies")
|
|||
opts_callback,
|
||||
c,
|
||||
{
|
||||
// Entry state is line 0
|
||||
symex_eventt::resume(symex_eventt::enumt::NEXT, 0),
|
||||
|
||||
// First the path where we enter the if-block at line 4 then on hitting
|
||||
// the branch at line 6 consider skipping straight to the end, but find
|
||||
// nothing there to investigate:
|
||||
|
@ -257,7 +272,9 @@ SCENARIO("path strategies")
|
|||
"lifo",
|
||||
no_halt_callback,
|
||||
c,
|
||||
{symex_eventt::resume(symex_eventt::enumt::JUMP, 7),
|
||||
{// Entry state is line 0
|
||||
symex_eventt::resume(symex_eventt::enumt::NEXT, 0),
|
||||
symex_eventt::resume(symex_eventt::enumt::JUMP, 7),
|
||||
symex_eventt::result(symex_eventt::enumt::FAILURE),
|
||||
symex_eventt::resume(symex_eventt::enumt::NEXT, 5),
|
||||
symex_eventt::result(symex_eventt::enumt::FAILURE),
|
||||
|
@ -270,7 +287,9 @@ SCENARIO("path strategies")
|
|||
"lifo",
|
||||
halt_callback,
|
||||
c,
|
||||
{symex_eventt::resume(symex_eventt::enumt::JUMP, 7),
|
||||
{// Entry state is line 0
|
||||
symex_eventt::resume(symex_eventt::enumt::NEXT, 0),
|
||||
symex_eventt::resume(symex_eventt::enumt::JUMP, 7),
|
||||
symex_eventt::result(symex_eventt::enumt::FAILURE),
|
||||
// Overall result
|
||||
symex_eventt::result(symex_eventt::enumt::FAILURE)});
|
||||
|
@ -283,24 +302,24 @@ SCENARIO("path strategies")
|
|||
|
||||
void symex_eventt::validate_result(
|
||||
listt &events,
|
||||
const safety_checkert::resultt result,
|
||||
const incremental_goto_checkert::resultt::progresst result,
|
||||
std::size_t &counter)
|
||||
{
|
||||
INFO(
|
||||
"Expecting result to be '"
|
||||
<< (result == safety_checkert::resultt::SAFE ? "success" : "failure")
|
||||
<< (result == incremental_goto_checkert::resultt::progresst::DONE
|
||||
? "success"
|
||||
: "failure")
|
||||
<< "' (item at index [" << counter << "] in expected results list");
|
||||
++counter;
|
||||
|
||||
REQUIRE(result != safety_checkert::resultt::ERROR);
|
||||
|
||||
if(result == safety_checkert::resultt::SAFE)
|
||||
if(result == incremental_goto_checkert::resultt::progresst::DONE)
|
||||
{
|
||||
REQUIRE(!events.empty());
|
||||
REQUIRE(events.front().first == symex_eventt::enumt::SUCCESS);
|
||||
events.pop_front();
|
||||
}
|
||||
else if(result == safety_checkert::resultt::UNSAFE)
|
||||
else
|
||||
{
|
||||
REQUIRE(!events.empty());
|
||||
REQUIRE(events.front().first == symex_eventt::enumt::FAILURE);
|
||||
|
@ -315,17 +334,11 @@ void symex_eventt::validate_resume(
|
|||
{
|
||||
REQUIRE(!events.empty());
|
||||
|
||||
int dst = std::stoi(state.saved_target->source_location.get_line().c_str());
|
||||
int dst = 0;
|
||||
if(!state.saved_target->source_location.get_line().empty())
|
||||
dst = std::stoi(state.saved_target->source_location.get_line().c_str());
|
||||
|
||||
if(state.has_saved_jump_target)
|
||||
{
|
||||
INFO(
|
||||
"Expecting resume to be 'jump' to line "
|
||||
<< dst << " (item at index [" << counter
|
||||
<< "] in expected resumes list)");
|
||||
REQUIRE(events.front().first == symex_eventt::enumt::JUMP);
|
||||
}
|
||||
else if(state.has_saved_next_instruction)
|
||||
if(state.has_saved_next_instruction)
|
||||
{
|
||||
INFO(
|
||||
"Expecting resume to be 'next' to line "
|
||||
|
@ -333,6 +346,14 @@ void symex_eventt::validate_resume(
|
|||
<< "] in expected resumes list)");
|
||||
REQUIRE(events.front().first == symex_eventt::enumt::NEXT);
|
||||
}
|
||||
else if(state.has_saved_jump_target)
|
||||
{
|
||||
INFO(
|
||||
"Expecting resume to be 'jump' to line "
|
||||
<< dst << " (item at index [" << counter
|
||||
<< "] in expected resumes list)");
|
||||
REQUIRE(events.front().first == symex_eventt::enumt::JUMP);
|
||||
}
|
||||
else
|
||||
REQUIRE(false);
|
||||
|
||||
|
@ -342,11 +363,8 @@ void symex_eventt::validate_resume(
|
|||
events.pop_front();
|
||||
}
|
||||
|
||||
// This is a simplified version of bmct::do_language_agnostic_bmc, without all
|
||||
// the edge cases to deal with java programs, bytecode loaded on demand, etc. We
|
||||
// need to replicate some of this stuff because the worklist is a local variable
|
||||
// of do_language_agnostic_bmc, and we need to check the worklist every time
|
||||
// symex returns.
|
||||
// This is a simplified copy of single_path_symex_checkert
|
||||
// because we have to check the worklist every time goto-symex returns.
|
||||
void _check_with_strategy(
|
||||
const std::string &strategy,
|
||||
const std::string &program,
|
||||
|
@ -366,95 +384,122 @@ void _check_with_strategy(
|
|||
config.main = "main";
|
||||
config.set(cmdline);
|
||||
|
||||
optionst opts;
|
||||
cbmc_parse_optionst::set_default_options(opts);
|
||||
opts.set_option("paths", true);
|
||||
opts.set_option("exploration-strategy", strategy);
|
||||
|
||||
opts_callback(opts);
|
||||
|
||||
ui_message_handlert mh(cmdline, "path-explore");
|
||||
mh.set_verbosity(0);
|
||||
messaget log(mh);
|
||||
|
||||
optionst options;
|
||||
cbmc_parse_optionst::set_default_options(options);
|
||||
options.set_option("paths", true);
|
||||
options.set_option("exploration-strategy", strategy);
|
||||
REQUIRE(is_valid_path_strategy(strategy));
|
||||
opts_callback(options);
|
||||
|
||||
ui_message_handlert ui_message_handler(cmdline, "path-explore");
|
||||
ui_message_handler.set_verbosity(0);
|
||||
messaget log(ui_message_handler);
|
||||
|
||||
goto_modelt goto_model;
|
||||
int ret;
|
||||
ret = cbmc_parse_optionst::get_goto_program(
|
||||
goto_model, options, cmdline, log, ui_message_handler);
|
||||
REQUIRE(ret == -1);
|
||||
|
||||
symbol_tablet symex_symbol_table;
|
||||
namespacet ns(goto_model.get_symbol_table(), symex_symbol_table);
|
||||
propertiest properties(initialize_properties(goto_model));
|
||||
std::unique_ptr<path_storaget> worklist = get_path_strategy(strategy);
|
||||
guard_managert guard_manager;
|
||||
|
||||
goto_modelt gm;
|
||||
int ret;
|
||||
ret = cbmc_parse_optionst::get_goto_program(gm, opts, cmdline, log, mh);
|
||||
REQUIRE(ret == -1);
|
||||
{
|
||||
// Put initial state into the work list
|
||||
symex_target_equationt equation(ui_message_handler);
|
||||
symex_bmct symex(
|
||||
ui_message_handler,
|
||||
goto_model.get_symbol_table(),
|
||||
equation,
|
||||
options,
|
||||
*worklist,
|
||||
guard_manager);
|
||||
setup_symex(symex, ns, options, ui_message_handler);
|
||||
|
||||
namespacet ns(gm.get_symbol_table());
|
||||
solver_factoryt solver_factory(opts, ns, mh, false);
|
||||
std::unique_ptr<solver_factoryt::solvert> cbmc_solver =
|
||||
solver_factory.get_solver();
|
||||
prop_convt &initial_pc = cbmc_solver->prop_conv();
|
||||
std::function<bool(void)> callback = []() { return false; };
|
||||
symex.initialize_path_storage_from_entry_point_of(
|
||||
goto_symext::get_goto_function(goto_model), symex_symbol_table);
|
||||
}
|
||||
|
||||
safety_checkert::resultt overall_result = safety_checkert::resultt::SAFE;
|
||||
std::size_t expected_results_cnt = 0;
|
||||
|
||||
bmct bmc(
|
||||
opts,
|
||||
gm.get_symbol_table(),
|
||||
mh,
|
||||
initial_pc,
|
||||
*worklist,
|
||||
callback,
|
||||
guard_manager);
|
||||
safety_checkert::resultt tmp_result = bmc.run(gm);
|
||||
|
||||
if(tmp_result != safety_checkert::resultt::PAUSED)
|
||||
{
|
||||
symex_eventt::validate_result(events, tmp_result, expected_results_cnt);
|
||||
overall_result &= tmp_result;
|
||||
}
|
||||
|
||||
if(
|
||||
overall_result == safety_checkert::resultt::UNSAFE &&
|
||||
opts.get_bool_option("stop-on-fail") && opts.is_set("paths"))
|
||||
{
|
||||
worklist->clear();
|
||||
}
|
||||
|
||||
while(!worklist->empty())
|
||||
{
|
||||
cbmc_solver = solver_factory.get_solver();
|
||||
prop_convt &pc = cbmc_solver->prop_conv();
|
||||
path_storaget::patht &resume = worklist->peek();
|
||||
|
||||
symex_eventt::validate_resume(events, resume.state, expected_results_cnt);
|
||||
|
||||
path_explorert pe(
|
||||
opts,
|
||||
gm.get_symbol_table(),
|
||||
mh,
|
||||
pc,
|
||||
symex_bmct symex(
|
||||
ui_message_handler,
|
||||
goto_model.get_symbol_table(),
|
||||
resume.equation,
|
||||
resume.state,
|
||||
options,
|
||||
*worklist,
|
||||
guard_manager,
|
||||
callback);
|
||||
tmp_result = pe.run(gm);
|
||||
guard_manager);
|
||||
setup_symex(symex, ns, options, ui_message_handler);
|
||||
|
||||
if(tmp_result != safety_checkert::resultt::PAUSED)
|
||||
symex.resume_symex_from_saved_state(
|
||||
goto_symext::get_goto_function(goto_model),
|
||||
resume.state,
|
||||
&resume.equation,
|
||||
symex_symbol_table);
|
||||
postprocess_equation(
|
||||
symex, resume.equation, options, ns, ui_message_handler);
|
||||
|
||||
incremental_goto_checkert::resultt result(
|
||||
incremental_goto_checkert::resultt::progresst::DONE);
|
||||
|
||||
if(symex.get_remaining_vccs() > 0)
|
||||
{
|
||||
symex_eventt::validate_result(events, tmp_result, expected_results_cnt);
|
||||
overall_result &= tmp_result;
|
||||
update_properties_status_from_symex_target_equation(
|
||||
properties, result.updated_properties, resume.equation);
|
||||
|
||||
goto_symex_property_decidert property_decider(
|
||||
options, ui_message_handler, resume.equation, ns);
|
||||
|
||||
const auto solver_runtime = prepare_property_decider(
|
||||
properties, resume.equation, property_decider, ui_message_handler);
|
||||
|
||||
run_property_decider(
|
||||
result,
|
||||
properties,
|
||||
property_decider,
|
||||
ui_message_handler,
|
||||
solver_runtime,
|
||||
false);
|
||||
|
||||
symex_eventt::validate_result(
|
||||
events, result.progress, expected_results_cnt);
|
||||
}
|
||||
|
||||
worklist->pop();
|
||||
|
||||
if(
|
||||
overall_result == safety_checkert::resultt::UNSAFE &&
|
||||
opts.get_bool_option("stop-on-fail"))
|
||||
result.progress ==
|
||||
incremental_goto_checkert::resultt::progresst::FOUND_FAIL &&
|
||||
options.get_bool_option("stop-on-fail"))
|
||||
{
|
||||
worklist->clear();
|
||||
}
|
||||
|
||||
if(worklist->empty())
|
||||
{
|
||||
update_status_of_not_checked_properties(
|
||||
properties, result.updated_properties);
|
||||
|
||||
update_status_of_unknown_properties(
|
||||
properties, result.updated_properties);
|
||||
}
|
||||
}
|
||||
|
||||
symex_eventt::validate_result(events, overall_result, expected_results_cnt);
|
||||
const resultt overall_result = determine_result(properties);
|
||||
symex_eventt::validate_result(
|
||||
events,
|
||||
overall_result == resultt::FAIL
|
||||
? incremental_goto_checkert::resultt::progresst::FOUND_FAIL
|
||||
: incremental_goto_checkert::resultt::progresst::DONE,
|
||||
expected_results_cnt);
|
||||
|
||||
INFO("The expected results list contains " << events.size() << " items");
|
||||
REQUIRE(events.empty());
|
||||
|
|
|
@ -6,7 +6,8 @@
|
|||
#define CPROVER_PATH_STRATEGIES_H
|
||||
|
||||
#include <goto-programs/goto_model.h>
|
||||
#include <goto-programs/safety_checker.h>
|
||||
|
||||
#include <goto-checker/incremental_goto_checker.h>
|
||||
|
||||
#include <goto-symex/goto_symex_state.h>
|
||||
|
||||
|
@ -38,7 +39,7 @@ public:
|
|||
|
||||
static void validate_result(
|
||||
listt &events,
|
||||
const safety_checkert::resultt result,
|
||||
const incremental_goto_checkert::resultt::progresst result,
|
||||
std::size_t &);
|
||||
|
||||
static void
|
||||
|
|
Loading…
Reference in New Issue