void equality_domaint::project_on_vars( valuet &value, const var_sett &vars, exprt &result) { #if 0 if(templ.size()==0) return domaint::project_on_vars(value, vars, result); #endif equ_valuet &v=static_cast<equ_valuet &>(value); exprt::operandst c; for(unsigned index=0; index<templ.size(); index++) { const var_pairt &vv=templ[index].var_pair; #if 0 std::cout << vv.second << std::endl; #endif if(vars.find(vv.first)==vars.end() || (vars.find(vv.second)==vars.end() && !(vv.second.id()==ID_constant && to_constant_expr(vv.second).get_value()=="NULL"))) continue; if(v.equs.same_set(vv.first, vv.second)) { if(templ[index].kind==LOOP) c.push_back( implies_exprt( templ[index].pre_guard, equal_exprt(vv.first, vv.second))); else c.push_back(equal_exprt(vv.first, vv.second)); } } for(index_sett::const_iterator it=v.disequs.begin(); it!=v.disequs.end(); it++) { const var_pairt &vv=templ[*it].var_pair; if(vars.find(vv.first)==vars.end() || (vars.find(vv.second)==vars.end() && !(vv.second.id()==ID_constant && to_constant_expr(vv.second).get_value()=="NULL"))) continue; if(templ[*it].kind==LOOP) c.push_back( implies_exprt( templ[*it].pre_guard, notequal_exprt(vv.first, vv.second))); else c.push_back(notequal_exprt(vv.first, vv.second)); } result=conjunction(c); }
void memory_model_sct::write_serialization_external( symex_target_equationt &equation) { for(address_mapt::const_iterator a_it=address_map.begin(); a_it!=address_map.end(); a_it++) { const a_rect &a_rec=a_it->second; // This is quadratic in the number of writes // per address. Perhaps some better encoding // based on 'places'? for(event_listt::const_iterator w_it1=a_rec.writes.begin(); w_it1!=a_rec.writes.end(); ++w_it1) { event_listt::const_iterator next=w_it1; ++next; for(event_listt::const_iterator w_it2=next; w_it2!=a_rec.writes.end(); ++w_it2) { // external? if((*w_it1)->source.thread_nr== (*w_it2)->source.thread_nr) continue; // ws is a total order, no two elements have the same rank // s -> w_evt1 before w_evt2; !s -> w_evt2 before w_evt1 symbol_exprt s=nondet_bool_symbol("ws-ext"); // write-to-write edge add_constraint( equation, implies_exprt(s, before(*w_it1, *w_it2)), "ws-ext", (*w_it1)->source); add_constraint( equation, implies_exprt(not_exprt(s), before(*w_it2, *w_it1)), "ws-ext", (*w_it1)->source); } } } }
/// post_guard=> (row_value=> row_expr) exprt predabs_domaint::get_row_post_constraint( const rowt &row, const row_valuet &row_value) { assert(row<templ.size()); const template_rowt &templ_row=templ[row]; if(templ_row.kind==IN) return true_exprt(); exprt c=implies_exprt( templ_row.post_guard, implies_exprt(row_value, templ[row].expr)); if(templ_row.kind==LOOP) rename(c); return c; }
void equality_domaint::make_not_post_constraints( valuet &_value, exprt::operandst &cond_exprs) { assert(*e_it<templ.size()); cond_exprs.resize(1); if(check_dis) { cond_exprs[0]=get_post_not_disequ_constraint(*e_it); return; } const template_rowt &templ_row=templ[*e_it]; if(templ_row.kind==IN) { cond_exprs[0]=true_exprt(); return; } const var_pairt &vv=templ_row.var_pair; exprt c= and_exprt( templ_row.aux_expr, not_exprt( implies_exprt( templ_row.post_guard, equal_exprt(vv.first, vv.second)))); rename(c); cond_exprs[0]=c; }
void summarizer_bwt::collect_postconditions( const function_namet &function_name, const local_SSAt &SSA, const summaryt &summary, exprt::operandst &postconditions, bool sufficient) { for(local_SSAt::nodest::const_iterator n_it = SSA.nodes.begin(); n_it != SSA.nodes.end(); n_it++) { for(local_SSAt::nodet::assertionst::const_iterator a_it = n_it->assertions.begin(); a_it != n_it->assertions.end(); a_it++) { postconditions.push_back(*a_it); } } /* if(termination) { if(!summary.termination_argument.is_nil()) postconditions.push_back(summary.termination_argument); }*/ exprt guard = SSA.guard_symbol(--SSA.goto_function.body.instructions.end()); if(!sufficient) postconditions.push_back(and_exprt(guard,summary.bw_postcondition)); else postconditions.push_back(implies_exprt(guard,summary.bw_postcondition)); }
void summarizer_fw_termt::do_nontermination( const function_namet &function_name, local_SSAt &SSA, summaryt &summary) { // calling context, invariant, function call summaries exprt::operandst cond; if(!summary.fw_invariant.is_nil()) cond.push_back(summary.fw_invariant); if(!summary.fw_precondition.is_nil()) cond.push_back(summary.fw_precondition); cond.push_back(ssa_inliner.get_summaries(SSA)); if(!check_end_reachable(function_name, SSA, conjunction(cond))) { status() << "Function never terminates normally" << eom; if(summary.fw_precondition.is_true()) summary.fw_transformer=false_exprt(); else summary.fw_transformer= implies_exprt(summary.fw_precondition, false_exprt()); summary.terminates=NO; } }
/// /\_all_rows ( pre_guard==> (row_value=> row_expr) ) exprt predabs_domaint::to_pre_constraints(valuet &_value) { assert(*e_it<templ.size()); const template_rowt &templ_row=templ[*e_it]; kindt k=templ_row.kind; if(k==OUT || k==OUTL) return true_exprt(); return implies_exprt(true_exprt(), templ[*e_it].expr); }
void local_SSAt::build_assertions(locationt loc) { if(loc->is_assert()) { exprt c=read_rhs(loc->guard, loc); exprt g=guard_symbol(loc); nodes[loc].assertion=implies_exprt(g, c); } }
exprt equality_domaint::get_pre_equ_constraint(unsigned index) { assert(index<templ.size()); const template_rowt &templ_row=templ[index]; if(templ_row.kind==OUT || templ_row.kind==OUTL) return true_exprt(); const var_pairt &vv=templ_row.var_pair; return implies_exprt(templ_row.pre_guard, equal_exprt(vv.first, vv.second)); }
/// pre_guard==> (row_value=> row_expr) exprt predabs_domaint::get_row_constraint( const rowt &row, const row_valuet &row_value) { assert(row<templ.size()); kindt k=templ[row].kind; if(k==OUT || k==OUTL) return true_exprt(); return implies_exprt(row_value, templ[row].expr); }
void predabs_domaint::project_on_vars( valuet &value, const var_sett &vars, exprt &result) { const templ_valuet &v=static_cast<const templ_valuet &>(value); assert(v.size()==templ.size()); exprt::operandst c; for(std::size_t row=0; row<templ.size(); row++) { const template_rowt &templ_row=templ[row]; std::set<symbol_exprt> symbols; find_symbols(templ_row.expr, symbols); bool pure=true; for(const auto &symbol : symbols) { if(vars.find(symbol)==vars.end()) { pure=false; break; } } if(!pure) continue; const row_valuet &row_v=v[row]; if(templ_row.kind==LOOP) { c.push_back( implies_exprt( templ_row.pre_guard, implies_exprt(row_v, templ_row.expr))); } else { c.push_back(implies_exprt(row_v, templ_row.expr)); } } result=conjunction(c); }
exprt equality_domaint::to_pre_constraints(valuet &_value) { if(check_dis) return get_pre_disequ_constraint(*e_it); assert(*e_it<templ.size()); const template_rowt &templ_row=templ[*e_it]; if(templ_row.kind==OUT || templ_row.kind==OUTL) return true_exprt(); const var_pairt &vv=templ_row.var_pair; return implies_exprt(templ_row.pre_guard, equal_exprt(vv.first, vv.second)); }
exprt polynomial_acceleratort::precondition(patht &path) { exprt ret = false_exprt(); for (patht::reverse_iterator r_it = path.rbegin(); r_it != path.rend(); ++r_it) { goto_programt::const_targett t = r_it->loc; if (t->is_assign()) { // XXX Need to check for aliasing... const code_assignt &assignment = to_code_assign(t->code); const exprt &lhs = assignment.lhs(); const exprt &rhs = assignment.rhs(); if (lhs.id() == ID_symbol) { replace_expr(lhs, rhs, ret); } else if (lhs.id() == ID_index || lhs.id() == ID_dereference) { continue; } else { throw "Couldn't take WP of " + expr2c(lhs, ns) + " = " + expr2c(rhs, ns); } } else if (t->is_assume() || t->is_assert()) { ret = implies_exprt(t->guard, ret); } else { // Ignore. } if (!r_it->guard.is_true() && !r_it->guard.is_nil()) { // The guard isn't constant true, so we need to accumulate that too. ret = implies_exprt(r_it->guard, ret); } } simplify(ret, ns); return ret; }
void summarizer_fw_termt::do_termination( const function_namet &function_name, local_SSAt &SSA, summaryt &summary) { // calling context, invariant, function call summaries exprt::operandst cond; if(!summary.fw_invariant.is_nil()) cond.push_back(summary.fw_invariant); if(!summary.fw_precondition.is_nil()) cond.push_back(summary.fw_precondition); cond.push_back(ssa_inliner.get_summaries(SSA)); status() << "Synthesizing ranking function to prove termination" << eom; // solver incremental_solvert &solver=ssa_db.get_solver(function_name); solver.set_message_handler(get_message_handler()); template_generator_rankingt template_generator1( options, ssa_db, ssa_unwinder.get(function_name)); template_generator1.set_message_handler(get_message_handler()); template_generator1(solver.next_domain_number(), SSA, true); if(template_generator1.all_vars().empty()) return; // nothing to do get_assertions(SSA, cond); // add assertions as assumptions // compute ranking functions ssa_analyzert analyzer1; analyzer1.set_message_handler(get_message_handler()); analyzer1(solver, SSA, conjunction(cond), template_generator1); analyzer1.get_result( summary.termination_argument, template_generator1.all_vars()); // extract information whether a ranking function was found for all loops summary.terminates=check_termination_argument(summary.termination_argument); if(!summary.fw_precondition.is_true()) summary.termination_argument= implies_exprt(summary.fw_precondition, summary.termination_argument); // statistics solver_instances+=analyzer1.get_number_of_solver_instances(); solver_calls+=analyzer1.get_number_of_solver_calls(); termargs_computed++; }
exprt equality_domaint::get_post_not_disequ_constraint(unsigned index) { assert(index<templ.size()); const template_rowt &templ_row=templ[index]; if(templ_row.kind==IN) return true_exprt(); const var_pairt &vv=templ_row.var_pair; exprt c= and_exprt( templ_row.aux_expr, not_exprt( implies_exprt( templ_row.post_guard, notequal_exprt(vv.first, vv.second)))); rename(c); return c; }
void summarizer_fwt::do_summary(const function_namet &function_name, local_SSAt &SSA, summaryt &summary, exprt cond, bool context_sensitive) { status() << "Computing summary" << eom; // solver incremental_solvert &solver = ssa_db.get_solver(function_name); solver.set_message_handler(get_message_handler()); //analyze ssa_analyzert analyzer; analyzer.set_message_handler(get_message_handler()); template_generator_summaryt template_generator( options,ssa_db,ssa_unwinder.get(function_name)); template_generator.set_message_handler(get_message_handler()); template_generator(solver.next_domain_number(),SSA,true); exprt::operandst conds; conds.reserve(5); conds.push_back(cond); conds.push_back(summary.fw_precondition); conds.push_back(ssa_inliner.get_summaries(SSA)); #ifdef REUSE_INVARIANTS if(summary_db.exists(function_name)) //reuse existing invariants { const exprt &old_inv = summary_db.get(function_name).fw_invariant; exprt inv = ssa_unwinder.get(function_name).rename_invariant(old_inv); conds.push_back(inv); #if 0 std::ostringstream out; out << "(original inv)" << from_expr(SSA.ns,"",old_inv) << "\n"; debug() << out.str() << eom; out << "(renamed inv)" << from_expr(SSA.ns,"",inv)<<"\n"; debug() << out.str() << eom; #endif } #endif cond = conjunction(conds); bool assertions_check = false; //options.get_bool_option("k-induction"); bool assertions_hold = analyzer(solver,SSA,cond,template_generator, assertions_check); if(assertions_hold) { analyzer.get_result(summary.fw_transformer,template_generator.inout_vars()); analyzer.get_result(summary.fw_invariant,template_generator.loop_vars()); #ifdef SHOW_WHOLE_RESULT // to see all the custom template values exprt whole_result; analyzer.get_result(whole_result,template_generator.all_vars()); debug() << "whole result: " << from_expr(SSA.ns,"",whole_result) << eom; #endif if(context_sensitive && !summary.fw_precondition.is_true()) { summary.fw_transformer = implies_exprt(summary.fw_precondition,summary.fw_transformer); summary.fw_invariant = implies_exprt(summary.fw_precondition,summary.fw_invariant); } } else //!assertions_hold { nonpassed_assertions = true; summary.nonpassed_assertions = analyzer.get_nonpassed_assertions(); } solver_instances += analyzer.get_number_of_solver_instances(); solver_calls += analyzer.get_number_of_solver_calls(); }
void memory_model_sct::from_read(symex_target_equationt &equation) { // from-read: (w', w) in ws and (w', r) in rf -> (r, w) in fr for(address_mapt::const_iterator a_it=address_map.begin(); a_it!=address_map.end(); a_it++) { const a_rect &a_rec=a_it->second; // This is quadratic in the number of writes per address. for(event_listt::const_iterator w_prime=a_rec.writes.begin(); w_prime!=a_rec.writes.end(); ++w_prime) { event_listt::const_iterator next=w_prime; ++next; for(event_listt::const_iterator w=next; w!=a_rec.writes.end(); ++w) { exprt ws1, ws2; if(po(*w_prime, *w) && !program_order_is_relaxed(*w_prime, *w)) { ws1=true_exprt(); ws2=false_exprt(); } else if(po(*w, *w_prime) && !program_order_is_relaxed(*w, *w_prime)) { ws1=false_exprt(); ws2=true_exprt(); } else { ws1=before(*w_prime, *w); ws2=before(*w, *w_prime); } // smells like cubic for(choice_symbolst::const_iterator c_it=choice_symbols.begin(); c_it!=choice_symbols.end(); c_it++) { event_it r=c_it->first.first; exprt rf=c_it->second; exprt cond; cond.make_nil(); if(c_it->first.second==*w_prime && !ws1.is_false()) { exprt fr=before(r, *w); // the guard of w_prime follows from rf; with rfi // optimisation such as the previous write_symbol_primed // it would even be wrong to add this guard cond= implies_exprt( and_exprt(r->guard, (*w)->guard, ws1, rf), fr); } else if(c_it->first.second==*w && !ws2.is_false()) { exprt fr=before(r, *w_prime); // the guard of w follows from rf; with rfi // optimisation such as the previous write_symbol_primed // it would even be wrong to add this guard cond= implies_exprt( and_exprt(r->guard, (*w_prime)->guard, ws2, rf), fr); } if(cond.is_not_nil()) add_constraint(equation, cond, "fr", r->source); } } } } }
void summarizer_bw_termt::do_summary_term( const function_namet &function_name, local_SSAt &SSA, const summaryt &old_summary, summaryt &summary, bool context_sensitive) { status() << "Computing preconditions for termination" << eom; // solver incremental_solvert &solver=ssa_db.get_solver(function_name); solver.set_message_handler(get_message_handler()); // templates for ranking functions template_generator_rankingt template_generator1( options, ssa_db, ssa_unwinder.get(function_name)); template_generator1.set_message_handler(get_message_handler()); template_generator1(solver.next_domain_number(), SSA, true); // templates for backward summary template_generator_summaryt template_generator2( options, ssa_db, ssa_unwinder.get(function_name)); template_generator2.set_message_handler(get_message_handler()); template_generator2(solver.next_domain_number(), SSA, false); exprt::operandst bindings; exprt::operandst postcond; // backward summaries ssa_inliner.get_summaries(SSA, false, postcond, bindings); collect_postconditions(function_name, SSA, summary, postcond, true); // prepare solver solver << SSA; solver.new_context(); solver << SSA.get_enabling_exprs(); solver << old_summary.fw_precondition; solver << old_summary.fw_invariant; solver << ssa_inliner.get_summaries(SSA); // forward summaries solver << conjunction(bindings); // bindings for backward summaries #if 0 // compute preconditions individually // TODO: this should be done more transparently for(unsigned i=0; i<postcond.size(); i++) { exprt::operandst postcond2; postcond2.push_back(postcond[i]); compute_precondition( SSA, summary, postcond2, solver, template_generator2, context_sensitive); } postcond.clear(); #endif if(template_generator1.all_vars().empty()) { compute_precondition( SSA, summary, postcond, solver, template_generator2, context_sensitive); solver.pop_context(); return; } summary.bw_precondition=false_exprt(); // initialize unsigned number_disjuncts=0; while(number_disjuncts++<MAX_PRECONDITION_DISJUNCTS) { // bootstrap preconditions exprt termination_argument; if(!bootstrap_preconditions( SSA, summary, solver, template_generator1, template_generator2, termination_argument)) { break; } // compute precondition // compute for individual termination arguments separately // TODO: this should be done more transparently if(termination_argument.id()==ID_and) { for(unsigned i=0; i<termination_argument.operands().size(); i++) { postcond.push_back(termination_argument.operands()[i]); exprt precondition= compute_precondition( SSA, summary, postcond, solver, template_generator2, context_sensitive); // join results if(summary.termination_argument.is_nil()) { summary.termination_argument= implies_exprt(precondition, termination_argument); } else { summary.termination_argument= and_exprt( summary.termination_argument, implies_exprt(precondition, termination_argument)); } // TODO: this is a bit asymmetric: // the first precondition is joined with all other sources // of non-termination (calls, bw calling context) postcond.clear(); } } else // do not split termination arguments { postcond.push_back(termination_argument); exprt precondition= compute_precondition( SSA, summary, postcond, solver, template_generator2, context_sensitive); // join results if(summary.termination_argument.is_nil()) { summary.termination_argument= implies_exprt(precondition, termination_argument); } else { summary.termination_argument= and_exprt( summary.termination_argument, implies_exprt(precondition, termination_argument)); } // TODO: this is a bit asymmetric: // the first precondition is joined with all other sources // of non-termination (calls, bw calling context) postcond.clear(); } } solver.pop_context(); }
void goto_checkt::pointer_validity_check( const dereference_exprt &expr, const guardt &guard) { if(!enable_pointer_check) return; const exprt &pointer=expr.op0(); const typet &pointer_type=to_pointer_type(ns.follow(pointer.type())); assert(base_type_eq(pointer_type.subtype(), expr.type(), ns)); local_bitvector_analysist::flagst flags= local_bitvector_analysis->get(t, pointer); const typet &dereference_type=pointer_type.subtype(); // For Java, we only need to check for null if(mode==ID_java) { if(flags.is_unknown() || flags.is_null()) { notequal_exprt not_eq_null(pointer, gen_zero(pointer.type())); add_guarded_claim( not_eq_null, "reference is null", "pointer dereference", expr.find_source_location(), expr, guard); } } else { if(flags.is_unknown() || flags.is_null()) { add_guarded_claim( not_exprt(null_pointer(pointer)), "dereference failure: pointer NULL", "pointer dereference", expr.find_source_location(), expr, guard); } if(flags.is_unknown()) add_guarded_claim( not_exprt(invalid_pointer(pointer)), "dereference failure: pointer invalid", "pointer dereference", expr.find_source_location(), expr, guard); if(flags.is_uninitialized()) add_guarded_claim( not_exprt(invalid_pointer(pointer)), "dereference failure: pointer uninitialized", "pointer dereference", expr.find_source_location(), expr, guard); if(mode != ID_java) { if(flags.is_unknown() || flags.is_dynamic_heap()) add_guarded_claim( not_exprt(deallocated(pointer, ns)), "dereference failure: deallocated dynamic object", "pointer dereference", expr.find_source_location(), expr, guard); if(flags.is_unknown() || flags.is_dynamic_local()) add_guarded_claim( not_exprt(dead_object(pointer, ns)), "dereference failure: dead object", "pointer dereference", expr.find_source_location(), expr, guard); } if(enable_bounds_check) { if(flags.is_unknown() || flags.is_dynamic_heap()) { exprt dynamic_bounds= or_exprt(dynamic_object_lower_bound(pointer), dynamic_object_upper_bound(pointer, dereference_type, ns)); add_guarded_claim( implies_exprt(malloc_object(pointer, ns), not_exprt(dynamic_bounds)), "dereference failure: dynamic object bounds", "pointer dereference", expr.find_source_location(), expr, guard); } } if(enable_bounds_check) { if(flags.is_unknown() || flags.is_dynamic_local() || flags.is_static_lifetime()) { exprt object_bounds= or_exprt(object_lower_bound(pointer), object_upper_bound(pointer, dereference_type, ns)); add_guarded_claim( or_exprt(dynamic_object(pointer), not_exprt(object_bounds)), "dereference failure: object bounds", "pointer dereference", expr.find_source_location(), expr, guard); } } } }
exprt summarizer_bw_termt::compute_precondition( local_SSAt &SSA, summaryt &summary, const exprt::operandst &postconditions, incremental_solvert &solver, template_generator_summaryt &template_generator, bool context_sensitive) { exprt postcond=not_exprt(conjunction(postconditions)); // compute backward summary exprt bw_transformer, bw_invariant, bw_precondition; if(!template_generator.out_vars().empty()) { ssa_analyzert analyzer; analyzer.set_message_handler(get_message_handler()); analyzer(solver, SSA, postcond, template_generator); analyzer.get_result(bw_transformer, template_generator.inout_vars()); analyzer.get_result(bw_invariant, template_generator.loop_vars()); analyzer.get_result(bw_precondition, template_generator.out_vars()); // statistics solver_instances+=analyzer.get_number_of_solver_instances(); solver_calls+=analyzer.get_number_of_solver_calls(); } #if 1 // TODO: yet another workaround for ssa_analyzer // not being able to handle empty templates properly else { solver << SSA; solver.new_context(); solver << SSA.get_enabling_exprs(); solver << postcond; exprt result=true_exprt(); if(solver()==decision_proceduret::D_UNSATISFIABLE) result=false_exprt(); solver.pop_context(); bw_transformer=result; bw_invariant=result; bw_precondition=result; } #endif bw_transformer=not_exprt(bw_transformer); bw_invariant=not_exprt(bw_invariant); bw_precondition=not_exprt(bw_precondition); if(context_sensitive && !summary.bw_postcondition.is_true()) { bw_transformer=implies_exprt(summary.bw_postcondition, bw_transformer); bw_invariant=implies_exprt(summary.bw_postcondition, bw_invariant); bw_precondition=implies_exprt(summary.bw_postcondition, bw_precondition); } // join // TODO: should go into summaryt if(summary.bw_transformer.is_nil()) { summary.bw_transformer=bw_transformer; summary.bw_invariant=bw_invariant; summary.bw_precondition=bw_precondition; } else { summary.bw_transformer=or_exprt(summary.bw_transformer, bw_transformer); summary.bw_invariant=or_exprt(summary.bw_invariant, bw_invariant); summary.bw_precondition=or_exprt(summary.bw_precondition, bw_precondition); } return bw_precondition; }
void summarizer_bwt::do_summary(const function_namet &function_name, local_SSAt &SSA, const summaryt &old_summary, summaryt &summary, bool context_sensitive) { bool sufficient = options.get_bool_option("sufficient"); status() << "Computing preconditions" << eom; // solver incremental_solvert &solver = ssa_db.get_solver(function_name); solver.set_message_handler(get_message_handler()); template_generator_summaryt template_generator( options,ssa_db,ssa_unwinder.get(function_name)); template_generator.set_message_handler(get_message_handler()); template_generator(solver.next_domain_number(),SSA,false); exprt::operandst c; c.push_back(old_summary.fw_precondition); c.push_back(old_summary.fw_invariant); c.push_back(ssa_inliner.get_summaries(SSA)); //forward summaries exprt::operandst postcond; ssa_inliner.get_summaries(SSA,false,postcond,c); //backward summaries collect_postconditions(function_name, SSA, summary, postcond,sufficient); if(!sufficient) { c.push_back(conjunction(postcond)); } else //sufficient { c.push_back(not_exprt(conjunction(postcond))); } if(!template_generator.out_vars().empty()) { ssa_analyzert analyzer; analyzer.set_message_handler(get_message_handler()); analyzer(solver,SSA,conjunction(c),template_generator); analyzer.get_result(summary.bw_transformer,template_generator.inout_vars()); analyzer.get_result(summary.bw_invariant,template_generator.loop_vars()); analyzer.get_result(summary.bw_precondition,template_generator.out_vars()); //statistics solver_instances += analyzer.get_number_of_solver_instances(); solver_calls += analyzer.get_number_of_solver_calls(); } else // TODO: yet another workaround for ssa_analyzer not being able to handle empty templates properly { solver << SSA; solver.new_context(); solver << SSA.get_enabling_exprs(); solver << conjunction(c); exprt result = true_exprt(); if(solver()==decision_proceduret::D_UNSATISFIABLE) result = false_exprt(); solver.pop_context(); summary.bw_transformer = result; summary.bw_invariant = result; summary.bw_precondition = result; } if(sufficient) { summary.bw_transformer = not_exprt(summary.bw_transformer); summary.bw_invariant = not_exprt(summary.bw_invariant); summary.bw_precondition = not_exprt(summary.bw_precondition); } if(context_sensitive && !summary.bw_postcondition.is_true()) { summary.bw_transformer = implies_exprt(summary.bw_postcondition,summary.bw_transformer); summary.bw_invariant = implies_exprt(summary.bw_postcondition,summary.bw_invariant); summary.bw_precondition = implies_exprt(summary.bw_postcondition,summary.bw_precondition); } }
bool refiner_wpt::refine_prefix( predicatest &predicates, abstract_modelt &abstract_model, const fail_infot &fail_info) { status("Refining set of predicates according to counterexample (WP)"); reset_num_predicates_added(); bool found_new=false; // keep track of the loops that we're in (may be nested) std::list<fail_infot::induction_infot> loops; exprt invariant; if(fail_info.use_invariants) status("Using recurrence predicates detected by loop detection."); print(10, "refiner_wpt::refine_prefix_async 1"); print(10, "Inconsistent prefix:"); for(abstract_counterexamplet::stepst::const_reverse_iterator r_it=fail_info.steps.rbegin(); r_it!=fail_info.steps.rend(); r_it++) { std::stringstream str; abstract_programt::targett abstract_pc=r_it->pc; goto_programt::const_targett concrete_pc= abstract_pc->code.concrete_pc; if(concrete_pc->is_goto()) str << "GUARD: " << (r_it->branch_taken?"(":"!(") << from_expr(concrete_model.ns, "", concrete_pc->guard) << ")"; else if(concrete_pc->is_assert()) str << "ASSERT: " << from_expr(concrete_model.ns, "", concrete_pc->guard); else if(concrete_pc->is_location()) str << "LOC" << std::endl; else if(concrete_pc->is_other() || concrete_pc->is_assign() || concrete_pc->is_decl()) str << from_expr(concrete_model.ns, "", concrete_pc->code); else { str << concrete_pc->type; } str << " // " << (concrete_pc->location); str << std::endl << "**********"; print(10, str.str()); } { // get the constraint causing the failure exprt predicate=fail_info.guard; #ifdef DEBUG std::cout << "P start0: " << from_expr(concrete_model.ns, "", predicate) << std::endl; #endif simplify(predicate, concrete_model.ns); abstract_counterexamplet::stepst::const_iterator it=--fail_info.steps.end(); // there must be at least two steps, or it's odd assert(it!=fail_info.steps.begin()); { abstract_programt::targett abstract_pc=it->pc; #ifdef DEBUG std::cout << "P start1: " << from_expr(concrete_model.ns, "", predicate) << std::endl; #endif add_predicates( abstract_pc, predicates, predicate, found_new, FROM); } // now do the WPs goto_symex_statet renaming_state; renaming_state.source.thread_nr=it->thread_nr; renaming_state.rename(predicate, concrete_model.ns, goto_symex_statet::L0); for(it--; // skip last instruction it!=fail_info.steps.begin(); it--) { #ifdef DEBUG std::cout << "refiner_wpt::refine_prefix_async 2\n"; #endif // handle loops if(fail_info.use_invariants) { if(it->is_loop_begin()) { loops.pop_back(); // pop induction_info if we leave loop #ifdef DEBUG std::cout << "INV: " << from_expr(concrete_model.ns, "", invariant) << std::endl; #endif exprt wp(ID_and, typet(ID_bool)); wp.operands().resize(2); wp.op0().swap(invariant); wp.op1().swap(predicate); predicate.swap(wp); } else if (it->is_loop_end()) { push_induction_info(fail_info, it, loops); invariant.make_true(); } } if(!it->is_state()) continue; if(predicate.is_true() && found_new) { // ok, refuted it, done break; } // add the predicate goto_programt::const_targett concrete_pc= it->pc->code.concrete_pc; abstract_programt::targett abstract_pc=it->pc; #ifdef DEBUG std::cout << from_expr(concrete_model.ns, "", predicate) << std::endl; #endif exprt no_tid_predicate=predicate; renaming_state.get_original_name(no_tid_predicate); add_predicates(abstract_pc, predicates, no_tid_predicate, found_new, TO); // skip irrelevant instructions if(!it->relevant) continue; exprt pred_bak=predicate; #ifdef DEBUG goto_programt tmp; tmp.output_instruction(concrete_model.ns, "", std::cerr, concrete_pc); #endif // compute weakest precondition switch(it->pc->type) { case ASSUME: // we only do this for assumptions // if we haven't found a new predicate so far if(1/*!found_new*/) { exprt tid_guard=concrete_pc->guard; renaming_state.source.thread_nr=it->thread_nr; renaming_state.rename(tid_guard, concrete_model.ns, goto_symex_statet::L0); predicate=implies_exprt(tid_guard, predicate); simplify(predicate, concrete_model.ns); } break; case GOTO: { exprt tid_guard=concrete_pc->guard; if(!it->branch_taken) tid_guard.make_not(); renaming_state.source.thread_nr=it->thread_nr; renaming_state.rename(tid_guard, concrete_model.ns, goto_symex_statet::L0); predicate=implies_exprt(tid_guard, predicate); simplify(predicate, concrete_model.ns); } break; case OTHER: /* Ignore if user-specified predicate, otherwise treat like assign */ if(it->pc->code.concrete_pc->code.get_statement()==ID_user_specified_predicate || it->pc->code.concrete_pc->code.get_statement()==ID_user_specified_parameter_predicates || it->pc->code.concrete_pc->code.get_statement()==ID_user_specified_return_predicates) break; case DECL: case ASSIGN: #ifdef DEBUG std::cout << "OTHER/ASSIGN/DECL\n"; #endif { codet tid_tmp_code; if(!fail_info.use_invariants || !get_instruction(concrete_pc, loops, tid_tmp_code, invariant)) tid_tmp_code=to_code(concrete_pc->code); #ifdef DEBUG std::cout << "A P before: " << from_expr(concrete_model.ns, "", predicate) << std::endl; std::cout << "Code: " << from_expr(concrete_model.ns, "", tid_tmp_code) << std::endl; #endif // compute weakest precondition if(tid_tmp_code.get_statement()==ID_assign) approximate_nondet(to_code_assign(tid_tmp_code).rhs()); renaming_state.source.thread_nr=it->thread_nr; renaming_state.rename(tid_tmp_code, concrete_model.ns, goto_symex_statet::L0); exprt predicate_wp=wp(tid_tmp_code, predicate, concrete_model.ns); simplify(predicate_wp, concrete_model.ns); predicate=predicate_wp; #ifdef DEBUG std::cout << "A P after: " << from_expr(concrete_model.ns, "", predicate) << std::endl; #endif } break; default: // ignore break; } #ifdef DEBUG std::cout << "B P to-check: " << from_expr(concrete_model.ns, "", predicate) << std::endl; #endif if(pred_bak != predicate) { satcheckt satcheck; bv_pointerst solver(concrete_model.ns, satcheck); solver.unbounded_array=boolbvt::U_NONE; literalt li=make_pos(concrete_model.ns, solver, predicate); satcheck.set_assumptions(bvt(1, li)); propt::resultt result=satcheck.prop_solve(); assert(propt::P_SATISFIABLE==result || propt::P_UNSATISFIABLE==result); if(propt::P_UNSATISFIABLE==result) predicate.make_false(); else { satcheck.set_assumptions(bvt(1, li.negation())); propt::resultt result=satcheck.prop_solve(); assert(propt::P_SATISFIABLE==result || propt::P_UNSATISFIABLE==result); if(propt::P_UNSATISFIABLE==result) { predicate.make_true(); if(it->pc->type==ASSIGN) { const codet &code=concrete_pc->code; if(code.get_statement()==ID_assign) { equal_exprt pred_new(to_code_assign(code).lhs(), to_code_assign(code).rhs()); simplify(pred_new, concrete_model.ns); #ifdef DEBUG std::cout << "Adding new predicate as we arrived at TRUE: " << from_expr(concrete_model.ns, "", pred_new) << std::endl; #endif no_tid_predicate=pred_new; renaming_state.get_original_name(no_tid_predicate); add_predicates(abstract_pc, predicates, no_tid_predicate, found_new, FROM); } } else if(it->pc->type==ASSUME || it->pc->type==GOTO) { exprt pred_new=concrete_pc->guard; simplify(pred_new, concrete_model.ns); #ifdef DEBUG std::cout << "Adding new predicate as we arrived at TRUE: " << from_expr(concrete_model.ns, "", pred_new) << std::endl; #endif no_tid_predicate=pred_new; renaming_state.get_original_name(no_tid_predicate); add_predicates(abstract_pc, predicates, no_tid_predicate, found_new, FROM); } } } } #ifdef DEBUG std::cout << "B P after: " << from_expr(concrete_model.ns, "", predicate) << std::endl; #endif no_tid_predicate=predicate; renaming_state.get_original_name(no_tid_predicate); add_predicates(abstract_pc, predicates, no_tid_predicate, found_new, FROM); } if(!predicate.is_true() && fail_info.warn_on_failure) { warning("Failed to refute spurious trace with WPs (got "+ from_expr(concrete_model.ns, "", predicate)+")"); } } if(found_new && fail_info.use_invariants) { add_induction_predicates( fail_info, abstract_model, predicates); } // make sure we have progress return !found_new; }