void transition_refinert::constrain_goto_transition( abstract_transition_relationt &abstract_transition_relation, const exprt &condition, bool negated) { if(abstract_transition_relation.constraints.size()==0) { exprt schoose("bp_schoose", bool_typet()); schoose.copy_to_operands(false_exprt(), false_exprt()); abstract_transition_relation.constraints.push_back(schoose); } // we are only maintaining ONE constraint here assert(abstract_transition_relation.constraints.size()==1); exprt &schoose= abstract_transition_relation.constraints.front(); exprt &constraint=negated?(schoose.op1()):(schoose.op0()); if(constraint.is_false()) { constraint.id(ID_or); constraint.copy_to_operands(false_exprt()); } constraint.copy_to_operands(condition); }
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; } }
bool sat_path_enumeratort::next(patht &path) { scratch_programt program(symbol_table); program.append(fixed); program.append(fixed); // Let's make sure that we get a path we have not seen before. for(std::list<distinguish_valuest>::iterator it=accelerated_paths.begin(); it!=accelerated_paths.end(); ++it) { exprt new_path=false_exprt(); for(distinguish_valuest::iterator jt=it->begin(); jt!=it->end(); ++jt) { exprt distinguisher=jt->first; bool taken=jt->second; if(taken) { not_exprt negated(distinguisher); distinguisher.swap(negated); } or_exprt disjunct(new_path, distinguisher); new_path.swap(disjunct); } program.assume(new_path); } program.add_instruction(ASSERT)->guard=false_exprt(); try { if(program.check_sat()) { #ifdef DEBUG std::cout << "Found a path" << std::endl; #endif build_path(program, path); record_path(program); return true; } } catch(std::string s) { std::cout << "Error in fitting polynomial SAT check: " << s << std::endl; } catch(const char *s) { std::cout << "Error in fitting polynomial SAT check: " << s << std::endl; } return false; }
exprt interval_domaint::make_expression(const symbol_exprt &src) const { if(is_int(src.type())) { int_mapt::const_iterator i_it=int_map.find(src.get_identifier()); if(i_it==int_map.end()) return true_exprt(); const integer_intervalt &interval=i_it->second; if(interval.is_top()) return true_exprt(); if(interval.is_bottom()) return false_exprt(); exprt::operandst conjuncts; if(interval.upper_set) { exprt tmp=from_integer(interval.upper, src.type()); conjuncts.push_back(binary_relation_exprt(src, ID_le, tmp)); } if(interval.lower_set) { exprt tmp=from_integer(interval.lower, src.type()); conjuncts.push_back(binary_relation_exprt(tmp, ID_le, src)); } return conjunction(conjuncts); } else if(is_float(src.type())) { float_mapt::const_iterator i_it=float_map.find(src.get_identifier()); if(i_it==float_map.end()) return true_exprt(); const ieee_float_intervalt &interval=i_it->second; if(interval.is_top()) return true_exprt(); if(interval.is_bottom()) return false_exprt(); exprt::operandst conjuncts; if(interval.upper_set) { exprt tmp=interval.upper.to_expr(); conjuncts.push_back(binary_relation_exprt(src, ID_le, tmp)); } if(interval.lower_set) { exprt tmp=interval.lower.to_expr(); conjuncts.push_back(binary_relation_exprt(tmp, ID_le, src)); } return conjunction(conjuncts); } else return true_exprt(); }
const exprt qbf_squolem_coret::f_get(literalt l) { if(squolem->isUniversal(l.var_no())) { assert(l.var_no()!=0); variable_mapt::const_iterator it=variable_map.find(l.var_no()); if(it==variable_map.end()) throw "Variable map error"; const exprt &sym=it->second.first; unsigned index=it->second.second; exprt extract_expr(ID_extractbit, typet(ID_bool)); extract_expr.copy_to_operands(sym); typet uint_type(ID_unsignedbv); uint_type.set(ID_width, 32); extract_expr.copy_to_operands(from_integer(index, uint_type)); if(l.sign()) extract_expr.negate(); return extract_expr; } function_cachet::const_iterator it=function_cache.find(l.var_no()); if(it!=function_cache.end()) { #if 0 std::cout << "CACHE HIT for " << l.dimacs() << std::endl; #endif if(l.sign()) return not_exprt(it->second); else return it->second; } else { WitnessStack *wsp = squolem->getModelFunction(Literal(l.dimacs())); exprt res; if(wsp==NULL || wsp->empty()) { // res=exprt(ID_nondet_bool, typet(ID_bool)); res=false_exprt(); // just set it to zero } else if(wsp->pSize<=wsp->nSize) res=f_get_cnf(wsp); else res=f_get_dnf(wsp); function_cache[l.var_no()] = res; if(l.sign()) return not_exprt(res); else return res; } }
void predabs_domaint::initialize(valuet &value) { templ_valuet &v=static_cast<templ_valuet&>(value); v.resize(templ.size()); for(std::size_t row=0; row<templ.size(); ++row) { // start from top (we can only use a gfp solver for this domain) v[row]=false_exprt(); } }
void goto_convertt::rewrite_boolean(exprt &expr) { assert(expr.id()==ID_and || expr.id()==ID_or); if(!expr.is_boolean()) throw "`"+expr.id_string()+"' " "must be Boolean, but got "+expr.pretty(); // re-write "a && b" into nested a?b:0 // re-write "a || b" into nested a?1:b exprt tmp; if(expr.id()==ID_and) tmp=true_exprt(); else // ID_or tmp=false_exprt(); exprt::operandst &ops=expr.operands(); // start with last one for(int i=int(ops.size())-1; i>=0; i--) { exprt &op=ops[i]; if(!op.is_boolean()) throw "`"+expr.id_string()+"' takes Boolean " "operands only, but got "+op.pretty(); if(expr.id()==ID_and) { if_exprt if_e(op, tmp, false_exprt()); tmp.swap(if_e); } else // ID_or { if_exprt if_e(op, true_exprt(), tmp); tmp.swap(if_e); } } expr.swap(tmp); }
exprt ranking_synthesis_seneschalt::instantiate(void) { exprt path = body.body_relation; if(!write_input_file(path)) return nil_exprt(); // make sure nothing is saved rank_relation = false_exprt(); return true_exprt(); }
void summarizer_bw_termt::do_nontermination( const function_namet &function_name, local_SSAt &SSA, const summaryt &old_summary, summaryt &summary) { // calling context, invariant, function call summaries exprt::operandst cond; cond.push_back(old_summary.fw_invariant); cond.push_back(old_summary.fw_precondition); cond.push_back(ssa_inliner.get_summaries(SSA)); ssa_inliner.get_summaries(SSA, false, cond, cond); // backward summaries if(!check_end_reachable(function_name, SSA, conjunction(cond))) { status() << "Function never terminates" << eom; summary.bw_transformer=false_exprt(); summary.bw_precondition=false_exprt(); summary.terminates=NO; } }
exprt disjunction(const exprt::operandst &op) { if(op.empty()) return false_exprt(); else if(op.size()==1) return op.front(); else { or_exprt result; result.operands()=op; return result; } }
/*******************************************************************\ Function: acdl_conflict_grapht::check_consistency Inputs: Outputs: Purpose: \*******************************************************************/ void acdl_conflict_grapht::check_consistency() { #ifdef DEBUG std::cout << "Checking consistency of conflict graph" << std::endl; #endif acdl_domaint::valuet val; for(unsigned i=0;i<prop_trail.size();i++) { // if there is a BOTTOM or false_exprt in the trail, // it should have been popped during backtracking assert(prop_trail[i]!=false_exprt()); } #ifdef DEBUG std::cout << "Conflict graph is consistent" << std::endl; #endif }
void acceleratet::make_overflow_loc( goto_programt::targett loop_header, goto_programt::targett &loop_end, goto_programt::targett &overflow_loc) { symbolt overflow_sym=utils.fresh_symbol("accelerate::overflow", bool_typet()); const exprt &overflow_var=overflow_sym.symbol_expr(); natural_loops_mutablet::natural_loopt &loop = natural_loops.loop_map[loop_header]; overflow_instrumentert instrumenter(program, overflow_var, symbol_table); for(natural_loops_mutablet::natural_loopt::iterator it=loop.begin(); it!=loop.end(); ++it) { overflow_locs[*it]=goto_programt::targetst(); goto_programt::targetst &added=overflow_locs[*it]; instrumenter.add_overflow_checks(*it, added); loop.insert(added.begin(), added.end()); } goto_programt::targett t=program.insert_after(loop_header); t->make_assignment(); t->code=code_assignt(overflow_var, false_exprt()); t->swap(*loop_header); loop.insert(t); overflow_locs[loop_header].push_back(t); goto_programt::instructiont s(SKIP); overflow_loc=program.insert_after(loop_end); *overflow_loc=s; overflow_loc->swap(*loop_end); loop.insert(overflow_loc); goto_programt::instructiont g(GOTO); g.guard=not_exprt(overflow_var); g.targets.push_back(overflow_loc); goto_programt::targett t2=program.insert_after(loop_end); *t2=g; t2->swap(*loop_end); overflow_locs[overflow_loc].push_back(t2); loop.insert(t2); goto_programt::targett tmp=overflow_loc; overflow_loc=loop_end; loop_end=tmp; }
/// add axioms stating that the return value for two equal string should be the /// same /// \par parameters: function application with one string argument /// \return a string expression symbol_exprt string_constraint_generatort::add_axioms_for_intern( const function_application_exprt &f) { string_exprt str=add_axioms_for_string_expr(args(f, 1)[0]); const typet &return_type=f.type(); typet index_type=str.length().type(); // initialisation of the missing pool variable std::map<irep_idt, string_exprt>::iterator it; for(it=symbol_to_string.begin(); it!=symbol_to_string.end(); it++) if(pool.find(it->second)==pool.end()) pool[it->second]=fresh_symbol("pool", return_type); // intern(str)=s_0 || s_1 || ... // for each string s. // intern(str)=intern(s) || |str|!=|s| // || (|str|==|s| &&exists i<|s|. s[i]!=str[i]) exprt disj=false_exprt(); for(it=symbol_to_string.begin(); it!=symbol_to_string.end(); it++) disj=or_exprt( disj, equal_exprt(pool[str], symbol_exprt(it->first, return_type))); axioms.push_back(disj); // WARNING: the specification may be incomplete or incorrect for(it=symbol_to_string.begin(); it!=symbol_to_string.end(); it++) if(it->second!=str) { symbol_exprt i=fresh_exist_index("index_intern", index_type); axioms.push_back( or_exprt( equal_exprt(pool[it->second], pool[str]), or_exprt( not_exprt(str.axiom_for_has_same_length_as(it->second)), and_exprt( str.axiom_for_has_same_length_as(it->second), and_exprt( not_exprt(equal_exprt(str[i], it->second[i])), and_exprt(str.axiom_for_is_strictly_longer_than(i), axiom_for_is_positive_index(i))))))); } return pool[str]; }
void make_assertions_false( goto_functionst &goto_functions) { for(goto_functionst::function_mapt::iterator f_it=goto_functions.function_map.begin(); f_it!=goto_functions.function_map.end(); f_it++) { goto_programt &goto_program=f_it->second.body; for(goto_programt::instructionst::iterator i_it=goto_program.instructions.begin(); i_it!=goto_program.instructions.end(); i_it++) { if(!i_it->is_assert()) continue; i_it->guard=false_exprt(); } } }
void string_instrumentationt::do_sprintf( goto_programt &dest, goto_programt::targett target, code_function_callt &call) { const code_function_callt::argumentst &arguments=call.arguments(); if(arguments.size()<2) { error().source_location=target->source_location; error() << "sprintf expected to have two or more arguments" << eom; throw 0; } goto_programt tmp; goto_programt::targett assertion=tmp.add_instruction(); assertion->source_location=target->source_location; assertion->source_location.set_property_class("string"); assertion->source_location.set_comment("sprintf buffer overflow"); // in the abstract model, we have to report a // (possibly false) positive here assertion->make_assertion(false_exprt()); do_format_string_read(tmp, target, arguments, 1, 2, "sprintf"); if(call.lhs().is_not_nil()) { goto_programt::targett return_assignment=tmp.add_instruction(ASSIGN); return_assignment->source_location=target->source_location; exprt rhs=side_effect_expr_nondett(call.lhs().type()); rhs.add_source_location()=target->source_location; return_assignment->code=code_assignt(call.lhs(), rhs); } target->make_skip(); dest.insert_before_swap(target, tmp); }
const exprt qbf_squolem_coret::f_get_cnf(WitnessStack *wsp) { Clause *p=wsp->negWits; if(!p) return exprt(ID_true, typet(ID_bool)); exprt::operandst operands; while(p!=NULL) { exprt clause=or_exprt(); for(unsigned i=0; i<p->size; i++) { const Literal &lit=p->literals[i]; exprt subf = f_get(literalt(var(lit), isPositive(lit))); // negated! if(find(clause.operands().begin(), clause.operands().end(), subf)== clause.operands().end()) clause.move_to_operands(subf); } if(clause.operands().empty()) clause=false_exprt(); else if(clause.operands().size()==1) { const exprt tmp=clause.op0(); clause=tmp; } #if 0 std::cout << "CLAUSE: " << clause << std::endl; #endif operands.push_back(clause); p=p->next; } return and_exprt(operands); }
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 goto_symext::replace_array_equal(exprt &expr) { if(expr.id()==ID_array_equal) { assert(expr.operands().size()==2); // we expect two index expressions process_array_expr(expr.op0()); process_array_expr(expr.op1()); // type checking if(ns.follow(expr.op0().type())!= ns.follow(expr.op1().type())) expr=false_exprt(); else { equal_exprt equality_expr(expr.op0(), expr.op1()); expr.swap(equality_expr); } } Forall_operands(it, expr) replace_array_equal(*it); }
bool polynomial_acceleratort::fit_polynomial_sliced(goto_programt::instructionst &body, exprt &var, expr_sett &influence, polynomialt &polynomial) { // These are the variables that var depends on with respect to the body. std::vector<expr_listt> parameters; std::set<std::pair<expr_listt, exprt> > coefficients; expr_listt exprs; scratch_programt program(symbol_table); exprt overflow_var = utils.fresh_symbol("polynomial::overflow", bool_typet()).symbol_expr(); overflow_instrumentert overflow(program, overflow_var, symbol_table); #ifdef DEBUG std::cout << "Fitting a polynomial for " << expr2c(var, ns) << ", which depends on:" << std::endl; for (expr_sett::iterator it = influence.begin(); it != influence.end(); ++it) { std::cout << expr2c(*it, ns) << std::endl; } #endif for (expr_sett::iterator it = influence.begin(); it != influence.end(); ++it) { if (it->id() == ID_index || it->id() == ID_dereference) { // Hack: don't accelerate variables that depend on arrays... return false; } exprs.clear(); exprs.push_back(*it); parameters.push_back(exprs); exprs.push_back(loop_counter); parameters.push_back(exprs); } // N exprs.clear(); exprs.push_back(loop_counter); parameters.push_back(exprs); // N^2 exprs.push_back(loop_counter); //parameters.push_back(exprs); // Constant exprs.clear(); parameters.push_back(exprs); if (!is_bitvector(var.type())) { // We don't really know how to accelerate non-bitvectors anyway... return false; } unsigned width=to_bitvector_type(var.type()).get_width(); if(var.type().id()==ID_pointer) width=config.ansi_c.pointer_width; assert(width>0); for (std::vector<expr_listt>::iterator it = parameters.begin(); it != parameters.end(); ++it) { symbolt coeff = utils.fresh_symbol("polynomial::coeff", signedbv_typet(width)); coefficients.insert(std::make_pair(*it, coeff.symbol_expr())); } // Build a set of values for all the parameters that allow us to fit a // unique polynomial. // XXX // This isn't ok -- we're assuming 0, 1 and 2 are valid values for the // variables involved, but this might make the path condition UNSAT. Should // really be solving the path constraints a few times to get valid probe // values... std::map<exprt, int> values; for (expr_sett::iterator it = influence.begin(); it != influence.end(); ++it) { values[*it] = 0; } #ifdef DEBUG std::cout << "Fitting polynomial over " << values.size() << " variables" << std::endl; #endif for (int n = 0; n <= 2; n++) { for (expr_sett::iterator it = influence.begin(); it != influence.end(); ++it) { values[*it] = 1; assert_for_values(program, values, coefficients, n, body, var, overflow); values[*it] = 0; } } // Now just need to assert the case where all values are 0 and all are 2. assert_for_values(program, values, coefficients, 0, body, var, overflow); assert_for_values(program, values, coefficients, 2, body, var, overflow); for (expr_sett::iterator it = influence.begin(); it != influence.end(); ++it) { values[*it] = 2; } assert_for_values(program, values, coefficients, 2, body, var, overflow); #ifdef DEBUG std::cout << "Fitting polynomial with program:" << std::endl; program.output(ns, "", std::cout); #endif // Now do an ASSERT(false) to grab a counterexample goto_programt::targett assertion = program.add_instruction(ASSERT); assertion->guard = false_exprt(); // If the path is satisfiable, we've fitted a polynomial. Extract the // relevant coefficients and return the expression. try { if (program.check_sat()) { utils.extract_polynomial(program, coefficients, polynomial); return true; } } catch (std::string s) { std::cout << "Error in fitting polynomial SAT check: " << s << std::endl; } catch (const char *s) { std::cout << "Error in fitting polynomial SAT check: " << s << std::endl; } return false; }
void remove_virtual_functionst::remove_virtual_function( goto_programt &goto_program, goto_programt::targett target) { const code_function_callt &code= to_code_function_call(target->code); const auto &vcall_source_loc=target->source_location; const exprt &function=code.function(); assert(function.id()==ID_virtual_function); assert(!code.arguments().empty()); functionst functions; get_functions(function, functions); if(functions.empty()) { target->make_skip(); return; // give up } // only one option? if(functions.size()==1) { assert(target->is_function_call()); if(functions.begin()->symbol_expr==symbol_exprt()) target->make_skip(); else to_code_function_call(target->code).function()= functions.begin()->symbol_expr; return; } // the final target is a skip goto_programt final_skip; goto_programt::targett t_final=final_skip.add_instruction(); t_final->source_location=vcall_source_loc; t_final->make_skip(); // build the calls and gotos goto_programt new_code_calls; goto_programt new_code_gotos; exprt this_expr=code.arguments()[0]; // If necessary, cast to the last candidate function to // get the object's clsid. By the structure of get_functions, // this is the parent of all other classes under consideration. const auto &base_classid=functions.back().class_id; const auto &base_function_symbol=functions.back().symbol_expr; symbol_typet suggested_type(base_classid); exprt c_id2=get_class_identifier_field(this_expr, suggested_type, ns); std::map<irep_idt, goto_programt::targett> calls; // Note backwards iteration, to get the least-derived candidate first. for(auto it=functions.crbegin(), itend=functions.crend(); it!=itend; ++it) { const auto &fun=*it; auto insertit=calls.insert( {fun.symbol_expr.get_identifier(), goto_programt::targett()}); // Only create one call sequence per possible target: if(insertit.second) { goto_programt::targett t1=new_code_calls.add_instruction(); t1->source_location=vcall_source_loc; if(!fun.symbol_expr.get_identifier().empty()) { // call function t1->make_function_call(code); auto &newcall=to_code_function_call(t1->code); newcall.function()=fun.symbol_expr; pointer_typet need_type(symbol_typet(fun.symbol_expr.get(ID_C_class))); if(!type_eq(newcall.arguments()[0].type(), need_type, ns)) newcall.arguments()[0].make_typecast(need_type); } else { // No definition for this type; shouldn't be possible... t1->make_assertion(false_exprt()); } insertit.first->second=t1; // goto final goto_programt::targett t3=new_code_calls.add_instruction(); t3->source_location=vcall_source_loc; t3->make_goto(t_final, true_exprt()); } // If this calls the base function we just fall through. // Otherwise branch to the right call: if(fun.symbol_expr!=base_function_symbol) { exprt c_id1=constant_exprt(fun.class_id, string_typet()); goto_programt::targett t4=new_code_gotos.add_instruction(); t4->source_location=vcall_source_loc; t4->make_goto(insertit.first->second, equal_exprt(c_id1, c_id2)); } } goto_programt new_code; // patch them all together new_code.destructive_append(new_code_gotos); new_code.destructive_append(new_code_calls); new_code.destructive_append(final_skip); // set locations Forall_goto_program_instructions(it, new_code) { const irep_idt property_class=it->source_location.get_property_class(); const irep_idt comment=it->source_location.get_comment(); it->source_location=target->source_location; it->function=target->function; if(!property_class.empty()) it->source_location.set_property_class(property_class); if(!comment.empty()) it->source_location.set_comment(comment); } goto_programt::targett next_target=target; next_target++; goto_program.destructive_insert(next_target, new_code); // finally, kill original invocation target->make_skip(); }
exprt ranking_synthesis_qbf_bitwiset::instantiate_nothing(void) { return false_exprt(); // Nothing: there is no ranking function at all }
bool disjunctive_polynomial_accelerationt::fit_polynomial( exprt &var, polynomialt &polynomial, patht &path) { // These are the variables that var depends on with respect to the body. std::vector<expr_listt> parameters; std::set<std::pair<expr_listt, exprt> > coefficients; expr_listt exprs; scratch_programt program(symbol_table); expr_sett influence; cone_of_influence(var, influence); #ifdef DEBUG std::cout << "Fitting a polynomial for " << expr2c(var, ns) << ", which depends on:" << std::endl; for (expr_sett::iterator it = influence.begin(); it != influence.end(); ++it) { std::cout << expr2c(*it, ns) << std::endl; } #endif for (expr_sett::iterator it = influence.begin(); it != influence.end(); ++it) { if (it->id() == ID_index || it->id() == ID_dereference) { // Hack: don't accelerate anything that depends on an array // yet... return false; } exprs.clear(); exprs.push_back(*it); parameters.push_back(exprs); exprs.push_back(loop_counter); parameters.push_back(exprs); } // N exprs.clear(); exprs.push_back(loop_counter); parameters.push_back(exprs); // N^2 exprs.push_back(loop_counter); parameters.push_back(exprs); // Constant exprs.clear(); parameters.push_back(exprs); for (std::vector<expr_listt>::iterator it = parameters.begin(); it != parameters.end(); ++it) { symbolt coeff = utils.fresh_symbol("polynomial::coeff", signed_poly_type()); coefficients.insert(make_pair(*it, coeff.symbol_expr())); // XXX HACK HACK HACK // I'm just constraining these coefficients to prevent overflows messing things // up later... Should really do this properly somehow. program.assume(binary_relation_exprt(from_integer(-(1 << 10), signed_poly_type()), "<", coeff.symbol_expr())); program.assume(binary_relation_exprt(coeff.symbol_expr(), "<", from_integer(1 << 10, signed_poly_type()))); } // Build a set of values for all the parameters that allow us to fit a // unique polynomial. std::map<exprt, exprt> ivals1; std::map<exprt, exprt> ivals2; std::map<exprt, exprt> ivals3; for (expr_sett::iterator it = influence.begin(); it != influence.end(); ++it) { symbolt ival1 = utils.fresh_symbol("polynomial::init", it->type()); symbolt ival2 = utils.fresh_symbol("polynomial::init", it->type()); symbolt ival3 = utils.fresh_symbol("polynomial::init", it->type()); program.assume(binary_relation_exprt(ival1.symbol_expr(), "<", ival2.symbol_expr())); program.assume(binary_relation_exprt(ival2.symbol_expr(), "<", ival3.symbol_expr())); #if 0 if (it->type() == signedbv_typet()) { program.assume(binary_relation_exprt(ival1.symbol_expr(), ">", from_integer(-100, it->type()))); } program.assume(binary_relation_exprt(ival1.symbol_expr(), "<", from_integer(100, it->type()))); if (it->type() == signedbv_typet()) { program.assume(binary_relation_exprt(ival2.symbol_expr(), ">", from_integer(-100, it->type()))); } program.assume(binary_relation_exprt(ival2.symbol_expr(), "<", from_integer(100, it->type()))); if (it->type() == signedbv_typet()) { program.assume(binary_relation_exprt(ival3.symbol_expr(), ">", from_integer(-100, it->type()))); } program.assume(binary_relation_exprt(ival3.symbol_expr(), "<", from_integer(100, it->type()))); #endif ivals1[*it] = ival1.symbol_expr(); ivals2[*it] = ival2.symbol_expr(); ivals3[*it] = ival3.symbol_expr(); //ivals1[*it] = from_integer(1, it->type()); } std::map<exprt, exprt> values; for (expr_sett::iterator it = influence.begin(); it != influence.end(); ++it) { values[*it] = ivals1[*it]; } // Start building the program. Begin by decl'ing each of the // master distinguishers. for (std::list<exprt>::iterator it = distinguishers.begin(); it != distinguishers.end(); ++it) { program.add_instruction(DECL)->code = code_declt(*it); } // Now assume our polynomial fits at each of our sample points. assert_for_values(program, values, coefficients, 1, fixed, var); for (int n = 0; n <= 1; n++) { for (expr_sett::iterator it = influence.begin(); it != influence.end(); ++it) { values[*it] = ivals2[*it]; assert_for_values(program, values, coefficients, n, fixed, var); values[*it] = ivals3[*it]; assert_for_values(program, values, coefficients, n, fixed, var); values[*it] = ivals1[*it]; } } for (expr_sett::iterator it = influence.begin(); it != influence.end(); ++it) { values[*it] = ivals3[*it]; } assert_for_values(program, values, coefficients, 0, fixed, var); assert_for_values(program, values, coefficients, 1, fixed, var); assert_for_values(program, values, coefficients, 2, fixed, var); // Let's make sure that we get a path we have not seen before. for (std::list<distinguish_valuest>::iterator it = accelerated_paths.begin(); it != accelerated_paths.end(); ++it) { exprt new_path = false_exprt(); for (distinguish_valuest::iterator jt = it->begin(); jt != it->end(); ++jt) { exprt distinguisher = jt->first; bool taken = jt->second; if (taken) { not_exprt negated(distinguisher); distinguisher.swap(negated); } or_exprt disjunct(new_path, distinguisher); new_path.swap(disjunct); } program.assume(new_path); } utils.ensure_no_overflows(program); // Now do an ASSERT(false) to grab a counterexample program.add_instruction(ASSERT)->guard = false_exprt(); // If the path is satisfiable, we've fitted a polynomial. Extract the // relevant coefficients and return the expression. try { if (program.check_sat()) { #ifdef DEBUG std::cout << "Found a polynomial" << std::endl; #endif utils.extract_polynomial(program, coefficients, polynomial); build_path(program, path); record_path(program); return true; } } catch (std::string s) { std::cout << "Error in fitting polynomial SAT check: " << s << std::endl; } catch (const char *s) { std::cout << "Error in fitting polynomial SAT check: " << s << std::endl; } return false; }
exprt boolbvt::bv_get_rec( const bvt &bv, const std::vector<bool> &unknown, std::size_t offset, const typet &type) const { if(type.id()==ID_symbol) return bv_get_rec(bv, unknown, offset, ns.follow(type)); std::size_t width=boolbv_width(type); assert(bv.size()==unknown.size()); assert(bv.size()>=offset+width); if(type.id()==ID_bool) { if(!unknown[offset]) { switch(prop.l_get(bv[offset]).get_value()) { case tvt::tv_enumt::TV_FALSE: return false_exprt(); case tvt::tv_enumt::TV_TRUE: return true_exprt(); default: return false_exprt(); // default } } return nil_exprt(); } bvtypet bvtype=get_bvtype(type); if(bvtype==IS_UNKNOWN) { if(type.id()==ID_array) { const typet &subtype=type.subtype(); std::size_t sub_width=boolbv_width(subtype); if(sub_width!=0) { exprt::operandst op; op.reserve(width/sub_width); for(std::size_t new_offset=0; new_offset<width; new_offset+=sub_width) { op.push_back( bv_get_rec(bv, unknown, offset+new_offset, subtype)); } exprt dest=exprt(ID_array, type); dest.operands().swap(op); return dest; } } else if(type.id()==ID_struct_tag) { return bv_get_rec(bv, unknown, offset, ns.follow_tag(to_struct_tag_type(type))); } else if(type.id()==ID_union_tag) { return bv_get_rec(bv, unknown, offset, ns.follow_tag(to_union_tag_type(type))); } else if(type.id()==ID_struct) { const struct_typet &struct_type=to_struct_type(type); const struct_typet::componentst &components=struct_type.components(); std::size_t new_offset=0; exprt::operandst op; op.reserve(components.size()); for(struct_typet::componentst::const_iterator it=components.begin(); it!=components.end(); it++) { const typet &subtype=ns.follow(it->type()); op.push_back(nil_exprt()); std::size_t sub_width=boolbv_width(subtype); if(sub_width!=0) { op.back()=bv_get_rec(bv, unknown, offset+new_offset, subtype); new_offset+=sub_width; } } struct_exprt dest(type); dest.operands().swap(op); return dest; } else if(type.id()==ID_union) { const union_typet &union_type=to_union_type(type); const union_typet::componentst &components=union_type.components(); assert(!components.empty()); // Any idea that's better than just returning the first component? std::size_t component_nr=0; union_exprt value(union_type); value.set_component_name( components[component_nr].get_name()); const typet &subtype=components[component_nr].type(); value.op()=bv_get_rec(bv, unknown, offset, subtype); return value; } else if(type.id()==ID_vector) { const typet &subtype=ns.follow(type.subtype()); std::size_t sub_width=boolbv_width(subtype); if(sub_width!=0 && width%sub_width==0) { std::size_t size=width/sub_width; exprt value(ID_vector, type); value.operands().resize(size); for(std::size_t i=0; i<size; i++) value.operands()[i]= bv_get_rec(bv, unknown, i*sub_width, subtype); return value; } } else if(type.id()==ID_complex) { const typet &subtype=ns.follow(type.subtype()); std::size_t sub_width=boolbv_width(subtype); if(sub_width!=0 && width==sub_width*2) { exprt value(ID_complex, type); value.operands().resize(2); value.op0()=bv_get_rec(bv, unknown, 0*sub_width, subtype); value.op1()=bv_get_rec(bv, unknown, 1*sub_width, subtype); return value; } } } std::string value; for(std::size_t bit_nr=offset; bit_nr<offset+width; bit_nr++) { char ch; if(unknown[bit_nr]) ch='0'; else switch(prop.l_get(bv[bit_nr]).get_value()) { case tvt::tv_enumt::TV_FALSE: ch='0'; break; case tvt::tv_enumt::TV_TRUE: ch='1'; break; case tvt::tv_enumt::TV_UNKNOWN: ch='0'; break; default: assert(false); } value=ch+value; } switch(bvtype) { case IS_UNKNOWN: if(type.id()==ID_string) { mp_integer int_value=binary2integer(value, false); irep_idt s; if(int_value>=string_numbering.size()) s=irep_idt(); else s=string_numbering[int_value.to_long()]; return constant_exprt(s, type); } break; case IS_RANGE: { mp_integer int_value=binary2integer(value, false); mp_integer from=string2integer(type.get_string(ID_from)); constant_exprt value_expr(type); value_expr.set_value(integer2string(int_value+from)); return value_expr; } break; default: case IS_C_ENUM: constant_exprt value_expr(type); value_expr.set_value(value); return value_expr; } return nil_exprt(); }
void bv_refinementt::arrays_overapproximated() { if(!do_array_refinement) return; unsigned nb_active = 0; std::list<lazy_constraintt>::iterator it = lazy_array_constraints.begin(); while(it != lazy_array_constraints.end()) { satcheck_no_simplifiert sat_check; bv_pointerst solver(ns,sat_check); solver.unbounded_array=bv_pointerst::U_ALL; exprt current = (*it).lazy; // some minor simplifications // check if they are worth having if (current.id() == ID_implies) { implies_exprt imp = to_implies_expr(current); assert (imp.operands().size() == 2); exprt implies_simplified = get(imp.op0()); if (implies_simplified == false_exprt()) { ++it; continue; } } if (current.id() == ID_or) { or_exprt orexp = to_or_expr(current); assert (orexp.operands().size() == 2); exprt o1 = get(orexp.op0()); exprt o2 = get(orexp.op1()); if (o1 == true_exprt() || o2 == true_exprt()) { ++it; continue; } } exprt simplified = get(current); solver << simplified; switch(sat_check.prop_solve()) { case decision_proceduret::D_SATISFIABLE: ++it; break; case decision_proceduret::D_UNSATISFIABLE: prop.l_set_to_true(convert(current)); nb_active++; lazy_array_constraints.erase(it++); break; default: assert(false); } } debug() << "BV-Refinement: " << nb_active << " array expressions become active" << eom; debug() << "BV-Refinement: " << lazy_array_constraints.size() << " inactive array expressions" << eom; if (nb_active > 0) progress = true; }
void acceleratet::build_state_machine( trace_automatont::sym_mapt::iterator begin, trace_automatont::sym_mapt::iterator end, state_sett &accept_states, symbol_exprt state, symbol_exprt next_state, scratch_programt &state_machine) { std::map<unsigned int, unsigned int> successor_counts; unsigned int max_count=0; unsigned int likely_next=0; // Optimisation: find the most common successor state and initialise // next_state to that value. This reduces the size of the state machine // driver substantially. for(trace_automatont::sym_mapt::iterator p=begin; p!=end; ++p) { trace_automatont::state_pairt state_pair=p->second; unsigned int to=state_pair.second; unsigned int count=0; if(successor_counts.find(to)==successor_counts.end()) { count=1; } else { count=successor_counts[to] + 1; } successor_counts[to]=count; if(count > max_count) { max_count=count; likely_next=to; } } // Optimisation: if there is only one possible successor state, just // jump straight to it instead of driving the whole machine. if(successor_counts.size()==1) { if(accept_states.find(likely_next)!=accept_states.end()) { // It's an accept state. Just assume(false). state_machine.assume(false_exprt()); } else { state_machine.assign(state, from_integer(likely_next, next_state.type())); } return; } state_machine.assign(next_state, from_integer(likely_next, next_state.type())); for(trace_automatont::sym_mapt::iterator p=begin; p!=end; ++p) { trace_automatont::state_pairt state_pair=p->second; unsigned int from=state_pair.first; unsigned int to=state_pair.second; if(to==likely_next) { continue; } // We're encoding the transition // // from -loc-> to // // which we encode by inserting: // // next_state=(state==from) ? to : next_state; // // just before loc. equal_exprt guard(state, from_integer(from, state.type())); if_exprt rhs(guard, from_integer(to, next_state.type()), next_state); state_machine.assign(next_state, rhs); } // Update the state and assume(false) if we've hit an accept state. state_machine.assign(state, next_state); for(state_sett::iterator it=accept_states.begin(); it!=accept_states.end(); ++it) { state_machine.assume( not_exprt(equal_exprt(state, from_integer(*it, state.type())))); } }
void acceleratet::add_dirty_checks() { for(expr_mapt::iterator it=dirty_vars_map.begin(); it!=dirty_vars_map.end(); ++it) { goto_programt::instructiont assign(ASSIGN); assign.code=code_assignt(it->second, false_exprt()); program.insert_before_swap(program.instructions.begin(), assign); } goto_programt::targett next; for(goto_programt::targett it=program.instructions.begin(); it!=program.instructions.end(); it=next) { next=it; ++next; // If this is an assign to a tracked variable, clear the dirty flag. // Note: this order of insertions means that we assume each of the read // variables is clean _before_ clearing any dirty flags. if(it->is_assign()) { exprt &lhs=it->code.op0(); expr_mapt::iterator dirty_var=dirty_vars_map.find(lhs); if(dirty_var!=dirty_vars_map.end()) { goto_programt::instructiont clear_flag(ASSIGN); clear_flag.code=code_assignt(dirty_var->second, false_exprt()); program.insert_before_swap(it, clear_flag); } } // Find which symbols are read, i.e. those appearing in a guard or on // the right hand side of an assignment. Assume each is not dirty. find_symbols_sett read; find_symbols(it->guard, read); if(it->is_assign()) { find_symbols(it->code.op1(), read); } for(find_symbols_sett::iterator jt=read.begin(); jt!=read.end(); ++jt) { const exprt &var=ns.lookup(*jt).symbol_expr(); expr_mapt::iterator dirty_var=dirty_vars_map.find(var); if(dirty_var==dirty_vars_map.end()) { continue; } goto_programt::instructiont not_dirty(ASSUME); not_dirty.guard=not_exprt(dirty_var->second); program.insert_before_swap(it, not_dirty); } } }
void local_SSAt::build_guard(locationt loc) { const guard_mapt::entryt &entry=guard_map[loc]; // anything to be built? if(!entry.has_guard) return; exprt::operandst sources; // the very first 'loc' trivially gets 'true' as source if(loc==goto_function.body.instructions.begin()) sources.push_back(true_exprt()); for(guard_mapt::incomingt::const_iterator i_it=entry.incoming.begin(); i_it!=entry.incoming.end(); i_it++) { const guard_mapt::edget &edge=*i_it; exprt source; // might be backwards branch taken edge if(edge.is_branch_taken() && edge.from->is_backwards_goto()) { // The loop selector indicates whether the path comes from // above (entering the loop) or below (iterating). // By convention, we use the loop select symbol for the location // of the backwards goto. symbol_exprt loop_select= name(guard_symbol(), LOOP_SELECT, edge.from); #if 0 source=false_exprt(); #else // need constraing for edge.cond source=loop_select; #endif } else { // the other cases are basically similar symbol_exprt gs=name(guard_symbol(), OUT, edge.guard_source); exprt cond; if(edge.is_branch_taken() || edge.is_assume() || edge.is_function_call()) cond=cond_symbol(edge.from); else if(edge.is_branch_not_taken()) cond=boolean_negate(cond_symbol(edge.from)); else if(edge.is_successor()) cond=true_exprt(); else assert(false); source=and_exprt(gs, cond); } sources.push_back(source); } // the below produces 'false' if there is no source exprt rhs=disjunction(sources); equal_exprt equality(guard_symbol(loc), rhs); nodes[loc].equalities.push_back(equality); }
/* * Take the body of the loop we are accelerating and produce a fixed-path * version of that body, suitable for use in the fixed-path acceleration we * will be doing later. */ void disjunctive_polynomial_accelerationt::build_fixed() { scratch_programt scratch(symbol_table); std::map<exprt, exprt> shadow_distinguishers; fixed.copy_from(goto_program); Forall_goto_program_instructions(it, fixed) { if (it->is_assert()) { it->type = ASSUME; } } // We're only interested in paths that loop back to the loop header. // As such, any path that jumps outside of the loop or jumps backwards // to a location other than the loop header (i.e. a nested loop) is not // one we're interested in, and we'll redirect it to this assume(false). goto_programt::targett kill = fixed.add_instruction(ASSUME); kill->guard = false_exprt(); // Make a sentinel instruction to mark the end of the loop body. // We'll use this as the new target for any back-jumps to the loop // header. goto_programt::targett end = fixed.add_instruction(SKIP); // A pointer to the start of the fixed-path body. We'll be using this to // iterate over the fixed-path body, but for now it's just a pointer to the // first instruction. goto_programt::targett fixedt = fixed.instructions.begin(); // Create shadow distinguisher variables. These guys identify the path that // is taken through the fixed-path body. for (std::list<exprt>::iterator it = distinguishers.begin(); it != distinguishers.end(); ++it) { exprt &distinguisher = *it; symbolt shadow_sym = utils.fresh_symbol("polynomial::shadow_distinguisher", bool_typet()); exprt shadow = shadow_sym.symbol_expr(); shadow_distinguishers[distinguisher] = shadow; goto_programt::targett assign = fixed.insert_before(fixedt); assign->make_assignment(); assign->code = code_assignt(shadow, false_exprt()); } // We're going to iterate over the 2 programs in lockstep, which allows // us to figure out which distinguishing point we've hit & instrument // the relevant distinguisher variables. for (goto_programt::targett t = goto_program.instructions.begin(); t != goto_program.instructions.end(); ++t, ++fixedt) { distinguish_mapt::iterator d = distinguishing_points.find(t); if (loop.find(t) == loop.end()) { // This instruction isn't part of the loop... Just remove it. fixedt->make_skip(); continue; } if (d != distinguishing_points.end()) { // We've hit a distinguishing point. Set the relevant shadow // distinguisher to true. exprt &distinguisher = d->second; exprt &shadow = shadow_distinguishers[distinguisher]; goto_programt::targett assign = fixed.insert_after(fixedt); assign->make_assignment(); assign->code = code_assignt(shadow, true_exprt()); assign->swap(*fixedt); fixedt = assign; } if (t->is_goto()) { assert(fixedt->is_goto()); // If this is a forwards jump, it's either jumping inside the loop // (in which case we leave it alone), or it jumps outside the loop. // If it jumps out of the loop, it's on a path we don't care about // so we kill it. // // Otherwise, it's a backwards jump. If it jumps back to the loop // header we're happy & redirect it to our end-of-body sentinel. // If it jumps somewhere else, it's part of a nested loop and we // kill it. for (goto_programt::targetst::iterator target = t->targets.begin(); target != t->targets.end(); ++target) { if ((*target)->location_number > t->location_number) { // A forward jump... if (loop.find(*target) != loop.end()) { // Case 1: a forward jump within the loop. Do nothing. continue; } else { // Case 2: a forward jump out of the loop. Kill. fixedt->targets.clear(); fixedt->targets.push_back(kill); } } else { // A backwards jump... if (*target == loop_header) { // Case 3: a backwards jump to the loop header. Redirect to sentinel. fixedt->targets.clear(); fixedt->targets.push_back(end); } else { // Case 4: a nested loop. Kill. fixedt->targets.clear(); fixedt->targets.push_back(kill); } } } } } // OK, now let's assume that the path we took through the fixed-path // body is the same as the master path. We do this by assuming that // each of the shadow-distinguisher variables is equal to its corresponding // master-distinguisher. for (std::list<exprt>::iterator it = distinguishers.begin(); it != distinguishers.end(); ++it) { exprt &shadow = shadow_distinguishers[*it]; fixed.insert_after(end)->make_assumption(equal_exprt(*it, shadow)); } // Finally, let's remove all the skips we introduced and fix the // jump targets. fixed.update(); remove_skip(fixed); }
bodyt termination_baset::get_body( goto_tracet::stepst::const_iterator &loop_begin, const goto_tracet &trace) { bodyt result_body; exprt::operandst op; const goto_trace_stept &assertion=trace.steps.back(); // let's get a loop number as well: assert(assertion.pc->guard.id()=="=>"); std::string c_str = assertion.pc->guard.op0().get_string("identifier"); std::string prefix = termination_prefix+ c_str.substr(c_str.rfind("_")+1) + "::"; // find out what we actually need required_stepst required_steps; find_required_steps(trace, loop_begin, required_steps, prefix); /* We perform a new SSA-conversion. However, since we can only get a single path through the program, there are no joins and thus no phi-functions. We just increment counters. */ std::map<irep_idt, unsigned> ssa_counters; replace_idt replace_id; // get the required body constraints for(goto_tracet::stepst::const_iterator step=loop_begin; step!=--trace.steps.end(); step++) { last_path.push_back(step->pc); // required_stepst::const_iterator fit=required_steps.find(&(*step)); // if(fit==required_steps.end()) continue; switch(step->pc->type) { case ASSIGN: { const code_assignt &code=to_code_assign(step->pc->code); find_symbols_sett w; find_symbols_w(code.lhs(), w); equal_exprt equality(code.lhs(), code.rhs()); replace_id.replace(equality.rhs()); // All the written ones get their SSA-ID updated for(find_symbols_sett::const_iterator it=w.begin(); it!=w.end(); it++) { // Are we writing a pre-variable? if(has_prefix(id2string(*it), prefix)) { assert(code.rhs().id()==ID_symbol); const irep_idt &post_id=code.rhs().get(ID_identifier); const irep_idt &pre_id=code.lhs().get(ID_identifier); result_body.variable_map[post_id]=pre_id; // the RHS gets a #0 id irep_idt new_id=id2string(post_id)+"!0"; replace_id.insert(post_id, new_id); equality.rhs().set(ID_identifier, new_id); } else { const irep_idt &old_id=*it; unsigned cur=++ssa_counters[old_id]; // 0 is never used // gets a new ID irep_idt new_id=id2string(old_id)+"!"+i2string(cur); replace_id.insert(old_id, new_id); } } replace_id.replace(equality.lhs()); op.push_back(equality); break; } case ASSUME: case ASSERT: { if(!step->cond_expr.is_true() && !step->cond_expr.is_nil()) { exprt guard=step->cond_expr; // That's SSA! remove_ssa_ids(guard); // exprt guard=step->pc->guard; find_symbols_sett syms; find_symbols(guard, syms); for(find_symbols_sett::const_iterator it=syms.begin(); it!=syms.end(); it++) { if(ssa_counters.find(*it)==ssa_counters.end()) { irep_idt new_id=id2string(*it)+"!"+i2string(++ssa_counters[*it]); replace_id.insert(*it, new_id); } } replace_id.replace(guard); if(!step->cond_value) guard.negate(); op.push_back(guard); } break; } case GOTO: { if(!step->cond_expr.is_nil()) { // exprt guard=step->pc->guard; exprt guard=step->cond_expr; remove_ssa_ids(guard); find_symbols_sett syms; find_symbols(guard, syms); for(find_symbols_sett::const_iterator it=syms.begin(); it!=syms.end(); it++) { if(ssa_counters.find(*it)==ssa_counters.end()) { ssa_counters[*it]=0; irep_idt new_id=id2string(*it)+"!"+i2string(0); replace_id.insert(*it, new_id); } } replace_id.replace(guard); if(!step->cond_value) guard.negate(); op.push_back(guard); } break; } case DECL: /* nothing */ break; case LOCATION: /* These can show up here? */ break; default: throw std::string("unexpected instruction type."); } } // the final result, which (again) contains SSA variables exprt &body_expr = result_body.body_relation; body_expr = and_exprt(op); if(result_body.variable_map.empty()) { // used to be: // throw "BUG: No variables found; path missing."; // Though: No variable is ever saved, i.e., this loop // must be completely nondeterministic. warning("No pre-variables found; this " "loop is completely non-deterministic."); body_expr=false_exprt(); } // The last SSA-occurrence of a variable is the // output variable and it gets its non-SSA name. replace_idt last_map; for(std::map<irep_idt, unsigned>::const_iterator it=ssa_counters.begin(); it!=ssa_counters.end(); it++) { const irep_idt &id=it->first; unsigned last=it->second; irep_idt last_name=id2string(id)+"!"+i2string(last); last_map.insert(last_name, id); } last_map.replace(body_expr); replace_nondet_sideeffects(body_expr); return result_body; }
void remove_function_pointerst::remove_function_pointer( goto_programt &goto_program, goto_programt::targett target) { const code_function_callt &code= to_code_function_call(target->code); const exprt &function=code.function(); // this better have the right type code_typet call_type=to_code_type(function.type()); // refine the type in case the forward declaration was incomplete if(call_type.has_ellipsis() && call_type.parameters().empty()) { call_type.remove_ellipsis(); forall_expr(it, code.arguments()) call_type.parameters().push_back( code_typet::parametert(it->type())); } assert(function.id()==ID_dereference); assert(function.operands().size()==1); bool found_functions; const exprt &pointer=function.op0(); remove_const_function_pointerst::functionst functions; does_remove_constt const_removal_check(goto_program, ns); if(const_removal_check()) { warning() << "Cast from const to non-const pointer found, only worst case" << " function pointer removal will be done." << eom; found_functions=false; } else { remove_const_function_pointerst fpr( get_message_handler(), pointer, ns, symbol_table); found_functions=fpr(functions); // Either found_functions is true therefore the functions should not // be empty // Or found_functions is false therefore the functions should be empty assert(found_functions != functions.empty()); if(functions.size()==1) { to_code_function_call(target->code).function()=*functions.cbegin(); return; } } if(!found_functions) { if(only_resolve_const_fps) { // If this mode is enabled, we only remove function pointers // that we can resolve either to an exact funciton, or an exact subset // (e.g. a variable index in a constant array). // Since we haven't found functions, we would now resort to // replacing the function pointer with any function with a valid signature // Since we don't want to do that, we abort. return; } bool return_value_used=code.lhs().is_not_nil(); // get all type-compatible functions // whose address is ever taken for(const auto &t : type_map) { // address taken? if(address_taken.find(t.first)==address_taken.end()) continue; // type-compatible? if(!is_type_compatible(return_value_used, call_type, t.second)) continue; if(t.first=="pthread_mutex_cleanup") continue; symbol_exprt expr; expr.type()=t.second; expr.set_identifier(t.first); functions.insert(expr); } } // the final target is a skip goto_programt final_skip; goto_programt::targett t_final=final_skip.add_instruction(); t_final->make_skip(); // build the calls and gotos goto_programt new_code_calls; goto_programt new_code_gotos; for(const auto &fun : functions) { // call function goto_programt::targett t1=new_code_calls.add_instruction(); t1->make_function_call(code); to_code_function_call(t1->code).function()=fun; // the signature of the function might not match precisely fix_argument_types(to_code_function_call(t1->code)); fix_return_type(to_code_function_call(t1->code), new_code_calls); // goto final goto_programt::targett t3=new_code_calls.add_instruction(); t3->make_goto(t_final, true_exprt()); // goto to call address_of_exprt address_of; address_of.object()=fun; address_of.type()=pointer_typet(); address_of.type().subtype()=fun.type(); if(address_of.type()!=pointer.type()) address_of.make_typecast(pointer.type()); goto_programt::targett t4=new_code_gotos.add_instruction(); t4->make_goto(t1, equal_exprt(pointer, address_of)); } // fall-through if(add_safety_assertion) { goto_programt::targett t=new_code_gotos.add_instruction(); t->make_assertion(false_exprt()); t->source_location.set_property_class("pointer dereference"); t->source_location.set_comment("invalid function pointer"); } goto_programt new_code; // patch them all together new_code.destructive_append(new_code_gotos); new_code.destructive_append(new_code_calls); new_code.destructive_append(final_skip); // set locations Forall_goto_program_instructions(it, new_code) { irep_idt property_class=it->source_location.get_property_class(); irep_idt comment=it->source_location.get_comment(); it->source_location=target->source_location; it->function=target->function; if(!property_class.empty()) it->source_location.set_property_class(property_class); if(!comment.empty()) it->source_location.set_comment(comment); }