Merge pull request #4217 from peterschrammel/move-bmct-jbmc

Move cbmc/bmc and all_properties to jbmc
This commit is contained in:
Peter Schrammel 2019-03-21 14:15:43 +00:00 committed by GitHub
commit 2e04b54cfc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 505 additions and 459 deletions

View File

@ -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

View File

@ -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();
}

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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>

View File

@ -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

View File

@ -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 \

View File

@ -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();
}

View File

@ -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;

View File

@ -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) \

View File

@ -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());

View File

@ -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