diff --git a/regression/cbmc/graphml_witness1/main.c b/regression/cbmc/graphml_witness1/main.c new file mode 100644 index 00000000000..585f39f87cf --- /dev/null +++ b/regression/cbmc/graphml_witness1/main.c @@ -0,0 +1,34 @@ +extern int __VERIFIER_nondet_int(void); + +typedef enum { + LIST_BEG, + LIST_END +} end_point_t; + +typedef enum { + ITEM_PREV, + ITEM_NEXT +} direction_t; + +void remove_one(end_point_t from) +{ + const direction_t next_field = (LIST_BEG == from) ? ITEM_NEXT : ITEM_PREV; +} + +end_point_t rand_end_point(void) +{ + _Bool choice; + if (choice) + return LIST_BEG; + else + return LIST_END; +} + +int main() +{ + remove_one(rand_end_point()); + + __CPROVER_assert(0, ""); + + return 0; +} diff --git a/regression/cbmc/graphml_witness1/test.desc b/regression/cbmc/graphml_witness1/test.desc new file mode 100644 index 00000000000..9e7f5b42724 --- /dev/null +++ b/regression/cbmc/graphml_witness1/test.desc @@ -0,0 +1,78 @@ +CORE +main.c +--graphml-witness - +^EXIT=10$ +^SIGNAL=0$ +^VERIFICATION FAILED$ + + + + + path + + + false + + + false + + + false + + + false + + + false + + + 0 + + + + + + + + + + + + + + + + + + C + + + true + + + main.c + 21 + + + + main.c + 29 + main + + + + main.c + 15 + remove_one + + + true + + + main.c + 31 + + + +-- +^warning: ignoring diff --git a/src/cbmc/bmc.cpp b/src/cbmc/bmc.cpp index 4982c1e38b3..ba970e659c8 100644 --- a/src/cbmc/bmc.cpp +++ b/src/cbmc/bmc.cpp @@ -25,7 +25,7 @@ Author: Daniel Kroening, kroening@kroening.com #include #include -#include +#include #include #include @@ -106,20 +106,40 @@ void bmct::error_trace() } break; } +} - const std::string graphml=options.get_option("graphml-cex"); - if(!graphml.empty()) - { - graphmlt cex_graph; - convert(ns, goto_trace, cex_graph); +/*******************************************************************\ - if(graphml=="-") - write_graphml(cex_graph, std::cout); - else - { - std::ofstream out(graphml); - write_graphml(cex_graph, out); - } +Function: bmct::output_graphml + + Inputs: + + Outputs: + + Purpose: outputs witnesses in graphml format + +\*******************************************************************/ + +void bmct::output_graphml( + resultt result, + const goto_functionst &goto_functions) +{ + const std::string graphml=options.get_option("graphml-witness"); + if(graphml.empty()) + return; + + graphml_witnesst graphml_witness(ns); + if(result==UNSAFE) + graphml_witness(safety_checkert::error_trace); + else + return; + + if(graphml=="-") + write_graphml(graphml_witness.graph(), std::cout); + else + { + std::ofstream out(graphml); + write_graphml(graphml_witness.graph(), out); } } @@ -294,79 +314,77 @@ void bmct::show_program() std::cout << "\n" << "Program constraints:" << "\n"; - for(symex_target_equationt::SSA_stepst::const_iterator - it=equation.SSA_steps.begin(); - it!=equation.SSA_steps.end(); it++) + for(const auto &step : equation.SSA_steps) { - std::cout << "// " << it->source.pc->location_number << " "; - std::cout << it->source.pc->source_location.as_string() << "\n"; + std::cout << "// " << step.source.pc->location_number << " "; + std::cout << step.source.pc->source_location.as_string() << "\n"; - if(it->is_assignment()) + if(step.is_assignment()) { std::string string_value; - languages.from_expr(it->cond_expr, string_value); + languages.from_expr(step.cond_expr, string_value); std::cout << "(" << count << ") " << string_value << "\n"; - if(!it->guard.is_true()) + if(!step.guard.is_true()) { - languages.from_expr(it->guard, string_value); + languages.from_expr(step.guard, string_value); std::cout << std::string(i2string(count).size()+3, ' '); std::cout << "guard: " << string_value << "\n"; } count++; } - else if(it->is_assert()) + else if(step.is_assert()) { std::string string_value; - languages.from_expr(it->cond_expr, string_value); + languages.from_expr(step.cond_expr, string_value); std::cout << "(" << count << ") ASSERT(" << string_value <<") " << "\n"; - if(!it->guard.is_true()) + if(!step.guard.is_true()) { - languages.from_expr(it->guard, string_value); + languages.from_expr(step.guard, string_value); std::cout << std::string(i2string(count).size()+3, ' '); std::cout << "guard: " << string_value << "\n"; } count++; } - else if(it->is_assume()) + else if(step.is_assume()) { std::string string_value; - languages.from_expr(it->cond_expr, string_value); + languages.from_expr(step.cond_expr, string_value); std::cout << "(" << count << ") ASSUME(" << string_value <<") " << "\n"; - if(!it->guard.is_true()) + if(!step.guard.is_true()) { - languages.from_expr(it->guard, string_value); + languages.from_expr(step.guard, string_value); std::cout << std::string(i2string(count).size()+3, ' '); std::cout << "guard: " << string_value << "\n"; } count++; } - else if(it->is_constraint()) + else if(step.is_constraint()) { std::string string_value; - languages.from_expr(it->cond_expr, string_value); + languages.from_expr(step.cond_expr, string_value); std::cout << "(" << count << ") CONSTRAINT(" << string_value <<") " << "\n"; count++; } - else if(it->is_shared_read() || it->is_shared_write()) + else if(step.is_shared_read() || step.is_shared_write()) { std::string string_value; - languages.from_expr(it->ssa_lhs, string_value); - std::cout << "(" << count << ") SHARED_" << (it->is_shared_write()?"WRITE":"READ") << "(" + languages.from_expr(step.ssa_lhs, string_value); + std::cout << "(" << count << ") SHARED_" << (step.is_shared_write()?"WRITE":"READ") << "(" << string_value <<") " << "\n"; - if(!it->guard.is_true()) + if(!step.guard.is_true()) { - languages.from_expr(it->guard, string_value); + languages.from_expr(step.guard, string_value); std::cout << std::string(i2string(count).size()+3, ' '); std::cout << "guard: " << string_value << "\n"; } @@ -611,6 +629,7 @@ safety_checkert::resultt bmct::stop_on_fail( dynamic_cast(prop_conv), equation, ns); error_trace(); + output_graphml(UNSAFE, goto_functions); } report_failure(); diff --git a/src/cbmc/bmc.h b/src/cbmc/bmc.h index 7a396fecede..4a2f683b028 100644 --- a/src/cbmc/bmc.h +++ b/src/cbmc/bmc.h @@ -103,7 +103,10 @@ class bmct:public safety_checkert virtual void report_failure(); virtual void error_trace(); - + void output_graphml( + resultt result, + const goto_functionst &goto_functions); + bool cover( const goto_functionst &goto_functions, const optionst::value_listt &criteria); diff --git a/src/cbmc/cbmc_parse_options.cpp b/src/cbmc/cbmc_parse_options.cpp index 09f2f17812d..de1b7060898 100644 --- a/src/cbmc/cbmc_parse_options.cpp +++ b/src/cbmc/cbmc_parse_options.cpp @@ -454,8 +454,12 @@ void cbmc_parse_optionst::get_command_line_options(optionst &options) if(cmdline.isset("outfile")) options.set_option("outfile", cmdline.get_value("outfile")); - if(cmdline.isset("graphml-cex")) - options.set_option("graphml-cex", cmdline.get_value("graphml-cex")); + if(cmdline.isset("graphml-witness")) + { + options.set_option("graphml-witness", cmdline.get_value("graphml-witness")); + options.set_option("stop-on-fail", true); + options.set_option("trace", true); + } } /*******************************************************************\ @@ -1170,7 +1174,7 @@ void cbmc_parse_optionst::help() " --unwinding-assertions generate unwinding assertions\n" " --partial-loops permit paths with partial loops\n" " --no-pretty-names do not simplify identifiers\n" - " --graphml-cex filename write the counterexample in GraphML format to filename\n" + " --graphml-witness filename write the witness in GraphML format to filename\n" "\n" "Backend options:\n" " --dimacs generate CNF in DIMACS format\n" diff --git a/src/cbmc/cbmc_parse_options.h b/src/cbmc/cbmc_parse_options.h index 1a4b9477cfd..16ea202ba8c 100644 --- a/src/cbmc/cbmc_parse_options.h +++ b/src/cbmc/cbmc_parse_options.h @@ -53,7 +53,7 @@ class optionst; "(arrays-uf-always)(arrays-uf-never)" \ "(string-abstraction)(no-arch)(arch):" \ "(round-to-nearest)(round-to-plus-inf)(round-to-minus-inf)(round-to-zero)" \ - "(graphml-cex):" \ + "(graphml-witness):" \ "(localize-faults)(localize-faults-method):" \ "(floatbv)(all-claims)(all-properties)" // legacy, and will eventually disappear diff --git a/src/goto-programs/Makefile b/src/goto-programs/Makefile index 0b0119112f2..932508b0edf 100644 --- a/src/goto-programs/Makefile +++ b/src/goto-programs/Makefile @@ -15,7 +15,7 @@ SRC = goto_convert.cpp goto_convert_function_call.cpp \ compute_called_functions.cpp link_to_library.cpp \ remove_returns.cpp osx_fat_reader.cpp remove_complex.cpp \ goto_trace.cpp xml_goto_trace.cpp vcd_goto_trace.cpp \ - graphml_goto_trace.cpp remove_virtual_functions.cpp \ + graphml_witness.cpp remove_virtual_functions.cpp \ class_hierarchy.cpp show_goto_functions.cpp get_goto_model.cpp INCLUDES= -I .. diff --git a/src/goto-programs/graphml_goto_trace.h b/src/goto-programs/graphml_goto_trace.h deleted file mode 100644 index d9b5e1787fd..00000000000 --- a/src/goto-programs/graphml_goto_trace.h +++ /dev/null @@ -1,23 +0,0 @@ -/*******************************************************************\ - -Module: Traces of GOTO Programs - -Author: Daniel Kroening - -Date: January 2015 - -\*******************************************************************/ - -#ifndef CPROVER_GOTO_PROGRAMS_GRAPHML_GOTO_TRACE_H -#define CPROVER_GOTO_PROGRAMS_GRAPHML_GOTO_TRACE_H - -#include - -#include "goto_trace.h" - -void convert( - const namespacet &ns, - const goto_tracet &goto_trace, - graphmlt &graphml); - -#endif diff --git a/src/goto-programs/graphml_goto_trace.cpp b/src/goto-programs/graphml_witness.cpp similarity index 93% rename from src/goto-programs/graphml_goto_trace.cpp rename to src/goto-programs/graphml_witness.cpp index dc127cfb33b..f5236227de6 100644 --- a/src/goto-programs/graphml_goto_trace.cpp +++ b/src/goto-programs/graphml_witness.cpp @@ -1,11 +1,9 @@ /*******************************************************************\ -Module: Traces of GOTO Programs +Module: Witnesses for Traces and Proofs Author: Daniel Kroening - Date: January 2015 - \*******************************************************************/ #include @@ -14,11 +12,11 @@ Author: Daniel Kroening #include #include -#include "graphml_goto_trace.h" +#include "graphml_witness.h" /*******************************************************************\ -Function: remove_l0_l1 +Function: graphml_witnesst::remove_l0_l1 Inputs: @@ -28,7 +26,7 @@ Function: remove_l0_l1 \*******************************************************************/ -static void remove_l0_l1(exprt &expr) +void graphml_witnesst::remove_l0_l1(exprt &expr) { if(expr.id()==ID_symbol) { @@ -56,7 +54,7 @@ static void remove_l0_l1(exprt &expr) /*******************************************************************\ -Function: convert_assign_rec +Function: graphml_witnesst::convert_assign_rec Inputs: @@ -66,8 +64,7 @@ Function: convert_assign_rec \*******************************************************************/ -static std::string convert_assign_rec( - const namespacet &ns, +std::string graphml_witnesst::convert_assign_rec( const irep_idt &identifier, const code_assignt &assign) { @@ -86,7 +83,7 @@ static std::string convert_assign_rec( from_integer(i++, signedbv_typet(config.ansi_c.pointer_width)), type.subtype()); if(!result.empty()) result+=' '; - result+=convert_assign_rec(ns, identifier, code_assignt(index, *it)); + result+=convert_assign_rec(identifier, code_assignt(index, *it)); } } else if(assign.rhs().id()==ID_struct || @@ -116,7 +113,7 @@ static std::string convert_assign_rec( c_it->get_name(), it->type()); if(!result.empty()) result+=' '; - result+=convert_assign_rec(ns, identifier, code_assignt(member, *it)); + result+=convert_assign_rec(identifier, code_assignt(member, *it)); ++c_it; } } @@ -134,20 +131,17 @@ static std::string convert_assign_rec( /*******************************************************************\ -Function: convert +Function: graphml_witnesst::operator() Inputs: Outputs: - Purpose: + Purpose: counterexample witness \*******************************************************************/ -void convert( - const namespacet &ns, - const goto_tracet &goto_trace, - graphmlt &graphml) +void graphml_witnesst::operator()(const goto_tracet &goto_trace) { const graphmlt::node_indext sink=graphml.add_node(); graphml[sink].node_name="sink"; @@ -257,7 +251,7 @@ void convert( xmlt &val=edge.new_element("data"); val.set_attribute("key", "assumption"); code_assignt assign(it->lhs_object, it->lhs_object_value); - val.data=convert_assign_rec(ns, identifier, assign); + val.data=convert_assign_rec(identifier, assign); xmlt &val_s=edge.new_element("data"); val_s.set_attribute("key", "assumption.scope"); diff --git a/src/goto-programs/graphml_witness.h b/src/goto-programs/graphml_witness.h new file mode 100644 index 00000000000..412091a0c64 --- /dev/null +++ b/src/goto-programs/graphml_witness.h @@ -0,0 +1,42 @@ +/*******************************************************************\ + +Module: Witnesses for Traces and Proofs + +Author: Daniel Kroening + +\*******************************************************************/ + +#ifndef CPROVER_GOTO_PROGRAMS_GRAPHML_WITNESS_H +#define CPROVER_GOTO_PROGRAMS_GRAPHML_WITNESS_H + +#include + +#include "goto_trace.h" + +class graphml_witnesst +{ +public: + explicit graphml_witnesst(const namespacet &_ns) + : ns(_ns) + { + } + + void operator()(const goto_tracet &goto_trace); + + inline const graphmlt &graph() + { + return graphml; + } + +protected: + const namespacet &ns; + graphmlt graphml; + + void remove_l0_l1(exprt &expr); + std::string convert_assign_rec( + const irep_idt &identifier, + const code_assignt &assign); + +}; + +#endif diff --git a/src/xmllang/graphml.cpp b/src/xmllang/graphml.cpp index 343ce2d7bec..1a8530f7ae0 100644 --- a/src/xmllang/graphml.cpp +++ b/src/xmllang/graphml.cpp @@ -279,62 +279,37 @@ bool write_graphml(const graphmlt &src, std::ostream &os) graphml.set_attribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); graphml.set_attribute("xmlns", "http://graphml.graphdrawing.org/xmlns"); - // - { - xmlt &key=graphml.new_element("key"); - key.set_attribute("attr.name", "assumption"); - key.set_attribute("attr.type", "string"); - key.set_attribute("for", "edge"); - key.set_attribute("id", "assumption"); - } - - // + // + // "<command-line>" + // { xmlt &key=graphml.new_element("key"); - key.set_attribute("attr.name", "sourcecode"); + key.set_attribute("attr.name", "originFileName"); key.set_attribute("attr.type", "string"); key.set_attribute("for", "edge"); - key.set_attribute("id", "sourcecode"); - } + key.set_attribute("id", "originfile"); - // - { - xmlt &key=graphml.new_element("key"); - key.set_attribute("attr.name", "sourcecodeLanguage"); - key.set_attribute("attr.type", "string"); - key.set_attribute("for", "graph"); - key.set_attribute("id", "sourcecodelang"); + key.new_element("default").data=""; } - // + // { xmlt &key=graphml.new_element("key"); - key.set_attribute("attr.name", "control"); + key.set_attribute("attr.name", "invariant"); key.set_attribute("attr.type", "string"); - key.set_attribute("for", "edge"); - key.set_attribute("id", "control"); - } - - // - { - xmlt &key=graphml.new_element("key"); - key.set_attribute("attr.name", "startline"); - key.set_attribute("attr.type", "int"); - key.set_attribute("for", "edge"); - key.set_attribute("id", "startline"); + key.set_attribute("for", "node"); + key.set_attribute("id", "invariant"); } - // - // "<command-line>" - // + // { xmlt &key=graphml.new_element("key"); - key.set_attribute("attr.name", "originFileName"); + key.set_attribute("attr.name", "invariant.scope"); key.set_attribute("attr.type", "string"); - key.set_attribute("for", "edge"); - key.set_attribute("id", "originfile"); - - key.new_element("default").data=""; + key.set_attribute("for", "node"); + key.set_attribute("id", "invariant.scope"); } // @@ -350,7 +325,8 @@ bool write_graphml(const graphmlt &src, std::ostream &os) key.new_element("default").data="path"; } - // + // // false // { @@ -363,7 +339,8 @@ bool write_graphml(const graphmlt &src, std::ostream &os) key.new_element("default").data="false"; } - // + // // false // { @@ -402,7 +379,150 @@ bool write_graphml(const graphmlt &src, std::ostream &os) key.new_element("default").data="false"; } - // + // + // false + // + { + xmlt &key=graphml.new_element("key"); + key.set_attribute("attr.name", "enterLoopHead"); + key.set_attribute("attr.type", "boolean"); + key.set_attribute("for", "edge"); + key.set_attribute("id", "enterLoopHead"); + + key.new_element("default").data="false"; + } + + // + // TODO: format for multi-threaded programs not defined yet + { + xmlt &key=graphml.new_element("key"); + key.set_attribute("attr.name", "threadNumber"); + key.set_attribute("attr.type", "int"); + key.set_attribute("for", "node"); + key.set_attribute("id", "thread"); + + key.new_element("default").data="0"; + } + + // + { + xmlt &key=graphml.new_element("key"); + key.set_attribute("attr.name", "sourcecodeLanguage"); + key.set_attribute("attr.type", "string"); + key.set_attribute("for", "graph"); + key.set_attribute("id", "sourcecodelang"); + } + + // + { + xmlt &key=graphml.new_element("key"); + key.set_attribute("attr.name", "programFile"); + key.set_attribute("attr.type", "string"); + key.set_attribute("for", "graph"); + key.set_attribute("id", "programfile"); + } + + // + { + xmlt &key=graphml.new_element("key"); + key.set_attribute("attr.name", "programHash"); + key.set_attribute("attr.type", "string"); + key.set_attribute("for", "graph"); + key.set_attribute("id", "programhash"); + } + + // + { + xmlt &key=graphml.new_element("key"); + key.set_attribute("attr.name", "specification"); + key.set_attribute("attr.type", "string"); + key.set_attribute("for", "graph"); + key.set_attribute("id", "specification"); + } + + // + { + xmlt &key=graphml.new_element("key"); + key.set_attribute("attr.name", "architecture"); + key.set_attribute("attr.type", "string"); + key.set_attribute("for", "graph"); + key.set_attribute("id", "architecture"); + } + + // + { + xmlt &key=graphml.new_element("key"); + key.set_attribute("attr.name", "producer"); + key.set_attribute("attr.type", "string"); + key.set_attribute("for", "graph"); + key.set_attribute("id", "producer"); + } + + // + { + xmlt &key=graphml.new_element("key"); + key.set_attribute("attr.name", "sourcecode"); + key.set_attribute("attr.type", "string"); + key.set_attribute("for", "edge"); + key.set_attribute("id", "sourcecode"); + } + + // + { + xmlt &key=graphml.new_element("key"); + key.set_attribute("attr.name", "startline"); + key.set_attribute("attr.type", "int"); + key.set_attribute("for", "edge"); + key.set_attribute("id", "startline"); + } + + // + { + xmlt &key=graphml.new_element("key"); + key.set_attribute("attr.name", "control"); + key.set_attribute("attr.type", "string"); + key.set_attribute("for", "edge"); + key.set_attribute("id", "control"); + } + + // + { + xmlt &key=graphml.new_element("key"); + key.set_attribute("attr.name", "assumption"); + key.set_attribute("attr.type", "string"); + key.set_attribute("for", "edge"); + key.set_attribute("id", "assumption"); + } + + // + { + xmlt &key=graphml.new_element("key"); + key.set_attribute("attr.name", "assumption.resultfunction"); + key.set_attribute("attr.type", "string"); + key.set_attribute("for", "edge"); + key.set_attribute("id", "assumption.resultfunction"); + } + + // + { + xmlt &key=graphml.new_element("key"); + key.set_attribute("attr.name", "assumption.scope"); + key.set_attribute("attr.type", "string"); + key.set_attribute("for", "edge"); + key.set_attribute("id", "assumption.scope"); + } + + // { xmlt &key=graphml.new_element("key"); key.set_attribute("attr.name", "enterFunction"); @@ -411,7 +531,8 @@ bool write_graphml(const graphmlt &src, std::ostream &os) key.set_attribute("id", "enterFunction"); } - // + // { xmlt &key=graphml.new_element("key"); key.set_attribute("attr.name", "returnFromFunction"); @@ -420,17 +541,16 @@ bool write_graphml(const graphmlt &src, std::ostream &os) key.set_attribute("id", "returnFrom"); } + // { xmlt &key=graphml.new_element("key"); - key.set_attribute("attr.name", "threadNumber"); - key.set_attribute("attr.type", "int"); - key.set_attribute("for", "node"); - key.set_attribute("id", "thread"); - - key.new_element("default").data="0"; + key.set_attribute("attr.name", "witness-type"); + key.set_attribute("attr.type", "string"); + key.set_attribute("for", "graph"); + key.set_attribute("id", "witness-type"); } - xmlt &graph=graphml.new_element("graph"); graph.set_attribute("edgedefault", "directed");