/// add axioms stating that if two strings are equal then their hash codes are /// equals /// \par parameters: function application with a string argument /// \return a integer expression corresponding to the hash code of the string exprt string_constraint_generatort::add_axioms_for_hash_code( const function_application_exprt &f) { string_exprt str=add_axioms_for_string_expr(args(f, 1)[0]); 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(hash.find(it->second)==hash.end()) hash[it->second]=fresh_symbol("hash", return_type); // for each string s. either: // c1: hash(str)=hash(s) // c2: |str|!=|s| // c3: (|str|==|s| &&exists i<|s|. s[i]!=str[i]) // WARNING: the specification may be incomplete for(it=symbol_to_string.begin(); it!=symbol_to_string.end(); it++) { symbol_exprt i=fresh_exist_index("index_hash", index_type); equal_exprt c1(hash[it->second], hash[str]); not_exprt c2(equal_exprt(it->second.length(), str.length())); and_exprt c3( equal_exprt(it->second.length(), str.length()), 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)))); axioms.push_back(or_exprt(c1, or_exprt(c2, c3))); } return hash[str]; }
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)); }
exprt string_constraint_generatort::add_axioms_for_last_index_of_string( const string_exprt &str, const string_exprt &substring, const exprt &from_index) { const typet &index_type=str.length().type(); symbol_exprt offset=fresh_exist_index("index_of", index_type); symbol_exprt contains=fresh_boolean("contains_substring"); // We add axioms: // a1 : contains => |substring| >= length &&offset <= from_index // a2 : !contains => offset=-1 // a3 : forall 0 <= witness<substring.length, // contains => str[witness+offset]=substring[witness] implies_exprt a1( contains, and_exprt( str.axiom_for_is_longer_than(plus_exprt(substring.length(), offset)), binary_relation_exprt(offset, ID_le, from_index))); axioms.push_back(a1); implies_exprt a2( not_exprt(contains), equal_exprt(offset, from_integer(-1, index_type))); axioms.push_back(a2); symbol_exprt qvar=fresh_univ_index("QA_index_of_string", index_type); equal_exprt constr3(str[plus_exprt(qvar, offset)], substring[qvar]); string_constraintt a3(qvar, substring.length(), contains, constr3); axioms.push_back(a3); return offset; }
exprt local_SSAt::edge_guard(locationt from, locationt to) const { if(from->is_goto()) { // big question: taken or not taken? if(to==from->get_target()) return and_exprt(guard_symbol(from), cond_symbol(from)); else return and_exprt(guard_symbol(from), not_exprt(cond_symbol(from))); } else if(from->is_assume()) { return and_exprt(guard_symbol(from), cond_symbol(from)); } else return guard_symbol(from); }
/// 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]; }
exprt string_constraint_generatort::add_axioms_for_last_index_of( const string_exprt &str, const exprt &c, const exprt &from_index) { const refined_string_typet &ref_type=to_refined_string_type(str.type()); const typet &index_type=ref_type.get_index_type(); symbol_exprt index=fresh_exist_index("last_index_of", index_type); symbol_exprt contains=fresh_boolean("contains_in_last_index_of"); // We add axioms: // a1 : -1 <= i <= from_index // a2 : (i=-1 <=> !contains) // a3 : (contains => i <= from_index &&s[i]=c) // a4 : forall n. i+1 <= n < from_index +1 &&contains => s[n]!=c // a5 : forall m. 0 <= m < from_index +1 &&!contains => s[m]!=c exprt index1=from_integer(1, index_type); exprt minus1=from_integer(-1, index_type); exprt from_index_plus_one=plus_exprt(from_index, index1); and_exprt a1( binary_relation_exprt(index, ID_ge, minus1), binary_relation_exprt(index, ID_lt, from_index_plus_one)); axioms.push_back(a1); equal_exprt a2(not_exprt(contains), equal_exprt(index, minus1)); axioms.push_back(a2); implies_exprt a3( contains, and_exprt( binary_relation_exprt(from_index, ID_ge, index), equal_exprt(str[index], c))); axioms.push_back(a3); symbol_exprt n=fresh_univ_index("QA_last_index_of", index_type); string_constraintt a4( n, plus_exprt(index, index1), from_index_plus_one, contains, not_exprt(equal_exprt(str[n], c))); axioms.push_back(a4); symbol_exprt m=fresh_univ_index("QA_last_index_of", index_type); string_constraintt a5( m, from_index_plus_one, not_exprt(contains), not_exprt(equal_exprt(str[m], c))); axioms.push_back(a5); return index; }
void predabs_domaint::make_not_post_constraints( const templ_valuet &value, exprt::operandst &cond_exprs) { assert(value.size()==templ.size()); cond_exprs.resize(templ.size()); exprt::operandst c; for(std::size_t row=0; row<templ.size(); row++) { cond_exprs[row]=and_exprt( templ[row].aux_expr, not_exprt(get_row_post_constraint(row, value))); } }
/// add axioms corresponding to the String.equalsIgnoreCase java function /// \par parameters: function application with two string arguments /// \return a Boolean expression exprt string_constraint_generatort::add_axioms_for_equals_ignore_case( const function_application_exprt &f) { assert(f.type()==bool_typet() || f.type().id()==ID_c_bool); symbol_exprt eq=fresh_boolean("equal_ignore_case"); typecast_exprt tc_eq(eq, f.type()); string_exprt s1=add_axioms_for_string_expr(args(f, 2)[0]); string_exprt s2=add_axioms_for_string_expr(args(f, 2)[1]); typet char_type=to_refined_string_type(s1.type()).get_char_type(); exprt char_a=constant_char('a', char_type); exprt char_A=constant_char('A', char_type); exprt char_Z=constant_char('Z', char_type); typet index_type=s1.length().type(); // We add axioms: // a1 : eq => |s1|=|s2| // a2 : forall qvar, 0<=qvar<|s1|, // eq => char_equal_ignore_case(s1[qvar],s2[qvar]); // a3 : !eq => |s1|!=s2 || (0 <=witness<|s1| &&!char_equal_ignore_case) implies_exprt a1(eq, s1.axiom_for_has_same_length_as(s2)); axioms.push_back(a1); symbol_exprt qvar=fresh_univ_index("QA_equal_ignore_case", index_type); exprt constr2=character_equals_ignore_case( s1[qvar], s2[qvar], char_a, char_A, char_Z); string_constraintt a2(qvar, s1.length(), eq, constr2); axioms.push_back(a2); symbol_exprt witness=fresh_exist_index( "witness_unequal_ignore_case", index_type); exprt zero=from_integer(0, witness.type()); and_exprt bound_witness( binary_relation_exprt(witness, ID_lt, s1.length()), binary_relation_exprt(witness, ID_ge, zero)); exprt witness_eq=character_equals_ignore_case( s1[witness], s2[witness], char_a, char_A, char_Z); not_exprt witness_diff(witness_eq); implies_exprt a3( not_exprt(eq), or_exprt( notequal_exprt(s1.length(), s2.length()), and_exprt(bound_witness, witness_diff))); axioms.push_back(a3); return tc_eq; }
void heap_tpolyhedra_domaint::project_on_vars( domaint::valuet &value, const domaint::var_sett &vars, exprt &result) { heap_tpolyhedra_valuet &v=static_cast<heap_tpolyhedra_valuet &>(value); exprt heap_result; heap_domain.project_on_vars(v.heap_value, vars, heap_result); exprt tpolyhedra_result; polyhedra_domain.project_on_vars(v.tpolyhedra_value, vars, tpolyhedra_result); result=heap_result; if(tpolyhedra_result!=true_exprt()) result=and_exprt(result, tpolyhedra_result); }
exprt string_constraint_generatort::add_axioms_for_index_of( const string_exprt &str, const exprt &c, const exprt &from_index) { const typet &index_type=str.length().type(); symbol_exprt index=fresh_exist_index("index_of", index_type); symbol_exprt contains=fresh_boolean("contains_in_index_of"); // We add axioms: // a1 : -1 <= index<|str| // a2 : !contains <=> index=-1 // a3 : contains => from_index<=index&&str[index]=c // a4 : forall n, from_index<=n<index. contains => str[n]!=c // a5 : forall m, from_index<=n<|str|. !contains => str[m]!=c exprt minus1=from_integer(-1, index_type); and_exprt a1( binary_relation_exprt(index, ID_ge, minus1), binary_relation_exprt(index, ID_lt, str.length())); axioms.push_back(a1); equal_exprt a2(not_exprt(contains), equal_exprt(index, minus1)); axioms.push_back(a2); implies_exprt a3( contains, and_exprt( binary_relation_exprt(from_index, ID_le, index), equal_exprt(str[index], c))); axioms.push_back(a3); symbol_exprt n=fresh_univ_index("QA_index_of", index_type); string_constraintt a4( n, from_index, index, contains, not_exprt(equal_exprt(str[n], c))); axioms.push_back(a4); symbol_exprt m=fresh_univ_index("QA_index_of", index_type); string_constraintt a5( m, from_index, str.length(), not_exprt(contains), not_exprt(equal_exprt(str[m], c))); axioms.push_back(a5); return index; }
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; }
const exprt qbf_squolem_coret::f_get_dnf(WitnessStack *wsp) { Clause *p=wsp->posWits; if(!p) return exprt(ID_false, typet(ID_bool)); exprt::operandst operands; while(p!=NULL) { exprt cube=and_exprt(); for(unsigned i=0; i<p->size; i++) { const Literal &lit=p->literals[i]; exprt subf = f_get(literalt(var(lit), !isPositive(lit))); if(find(cube.operands().begin(), cube.operands().end(), subf)== cube.operands().end()) cube.move_to_operands(subf); simplify_extractbits(cube); } if(cube.operands().empty()) cube=true_exprt(); else if(cube.operands().size()==1) { const exprt tmp=cube.op0(); cube=tmp; } #if 0 std::cout << "CUBE: " << cube << std::endl; #endif operands.push_back(cube); p=p->next; } return or_exprt(operands); }
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); }
bool polynomial_acceleratort::accelerate(patht &loop, path_acceleratort &accelerator) { goto_programt::instructionst body; accelerator.clear(); for (patht::iterator it = loop.begin(); it != loop.end(); ++it) { body.push_back(*(it->loc)); } expr_sett targets; std::map<exprt, polynomialt> polynomials; scratch_programt program(symbol_table); goto_programt::instructionst assigns; utils.find_modified(body, targets); #ifdef DEBUG std::cout << "Polynomial accelerating program:" << std::endl; for (goto_programt::instructionst::iterator it = body.begin(); it != body.end(); ++it) { program.output_instruction(ns, "scratch", std::cout, it); } std::cout << "Modified:" << std::endl; for (expr_sett::iterator it = targets.begin(); it != targets.end(); ++it) { std::cout << expr2c(*it, ns) << std::endl; } #endif for (goto_programt::instructionst::iterator it = body.begin(); it != body.end(); ++it) { if (it->is_assign() || it->is_decl()) { assigns.push_back(*it); } } if (loop_counter.is_nil()) { symbolt loop_sym = utils.fresh_symbol("polynomial::loop_counter", unsignedbv_typet(POLY_WIDTH)); loop_counter = loop_sym.symbol_expr(); } for (expr_sett::iterator it = targets.begin(); it != targets.end(); ++it) { polynomialt poly; exprt target = *it; expr_sett influence; goto_programt::instructionst sliced_assigns; if (target.type() == bool_typet()) { // Hack: don't accelerate booleans. continue; } cone_of_influence(assigns, target, sliced_assigns, influence); if (influence.find(target) == influence.end()) { #ifdef DEBUG std::cout << "Found nonrecursive expression: " << expr2c(target, ns) << std::endl; #endif nonrecursive.insert(target); continue; } if (target.id() == ID_index || target.id() == ID_dereference) { // We can't accelerate a recursive indirect access... accelerator.dirty_vars.insert(target); continue; } if (fit_polynomial_sliced(sliced_assigns, target, influence, poly)) { std::map<exprt, polynomialt> this_poly; this_poly[target] = poly; if (check_inductive(this_poly, assigns)) { polynomials.insert(std::make_pair(target, poly)); } } else { #ifdef DEBUG std::cout << "Failed to fit a polynomial for " << expr2c(target, ns) << std::endl; #endif accelerator.dirty_vars.insert(*it); } } if (polynomials.empty()) { //return false; } /* if (!utils.check_inductive(polynomials, assigns)) { // They're not inductive :-( return false; } */ substitutiont stashed; stash_polynomials(program, polynomials, stashed, body); exprt guard; exprt guard_last; bool path_is_monotone; try { path_is_monotone = utils.do_assumptions(polynomials, loop, guard); } catch (std::string s) { // Couldn't do WP. std::cout << "Assumptions error: " << s << std::endl; return false; } guard_last = guard; for (std::map<exprt, polynomialt>::iterator it = polynomials.begin(); it != polynomials.end(); ++it) { replace_expr(it->first, it->second.to_expr(), guard_last); } if (path_is_monotone) { // OK cool -- the path is monotone, so we can just assume the condition for // the first and last iterations. replace_expr(loop_counter, minus_exprt(loop_counter, from_integer(1, loop_counter.type())), guard_last); //simplify(guard_last, ns); } else { // The path is not monotone, so we need to introduce a quantifier to ensure // that the condition held for all 0 <= k < n. symbolt k_sym = utils.fresh_symbol("polynomial::k", unsignedbv_typet(POLY_WIDTH)); exprt k = k_sym.symbol_expr(); exprt k_bound = and_exprt(binary_relation_exprt(from_integer(0, k.type()), "<=", k), binary_relation_exprt(k, "<", loop_counter)); replace_expr(loop_counter, k, guard_last); implies_exprt implies(k_bound, guard_last); //simplify(implies, ns); exprt forall(ID_forall); forall.type() = bool_typet(); forall.copy_to_operands(k); forall.copy_to_operands(implies); guard_last = forall; } // All our conditions are met -- we can finally build the accelerator! // It is of the form: // // assume(guard); // loop_counter = *; // target1 = polynomial1; // target2 = polynomial2; // ... // assume(guard); // assume(no overflows in previous code); program.add_instruction(ASSUME)->guard = guard; program.assign(loop_counter, side_effect_expr_nondett(loop_counter.type())); for (std::map<exprt, polynomialt>::iterator it = polynomials.begin(); it != polynomials.end(); ++it) { program.assign(it->first, it->second.to_expr()); } // Add in any array assignments we can do now. if (!utils.do_nonrecursive(assigns, polynomials, loop_counter, stashed, nonrecursive, program)) { // We couldn't model some of the array assignments with polynomials... // Unfortunately that means we just have to bail out. #ifdef DEBUG std::cout << "Failed to accelerate a nonrecursive expression" << std::endl; #endif return false; } program.add_instruction(ASSUME)->guard = guard_last; program.fix_types(); if (path_is_monotone) { utils.ensure_no_overflows(program); } accelerator.pure_accelerator.instructions.swap(program.instructions); return true; }
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 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 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 goto_checkt::bounds_check( const index_exprt &expr, const guardt &guard) { if(!enable_bounds_check) return; if(expr.find("bounds_check").is_not_nil() && !expr.get_bool("bounds_check")) return; typet array_type=ns.follow(expr.array().type()); if(array_type.id()==ID_pointer) return; // done by the pointer code else if(array_type.id()==ID_incomplete_array) throw "index got incomplete array"; else if(array_type.id()!=ID_array && array_type.id()!=ID_vector) throw "bounds check expected array or vector type, got " +array_type.id_string(); std::string name=array_name(expr.array()); const exprt &index=expr.index(); object_descriptor_exprt ode; ode.build(expr, ns); if(index.type().id()!=ID_unsignedbv) { // we undo typecasts to signedbv if(index.id()==ID_typecast && index.operands().size()==1 && index.op0().type().id()==ID_unsignedbv) { // ok } else { mp_integer i; if(!to_integer(index, i) && i>=0) { // ok } else { exprt effective_offset=ode.offset(); if(ode.root_object().id()==ID_dereference) { exprt p_offset=pointer_offset( to_dereference_expr(ode.root_object()).pointer()); assert(p_offset.type()==effective_offset.type()); effective_offset=plus_exprt(p_offset, effective_offset); } exprt zero=gen_zero(ode.offset().type()); assert(zero.is_not_nil()); // the final offset must not be negative binary_relation_exprt inequality(effective_offset, ID_ge, zero); add_guarded_claim( inequality, name+" lower bound", "array bounds", expr.find_source_location(), expr, guard); } } } if(ode.root_object().id()==ID_dereference) { const exprt &pointer= to_dereference_expr(ode.root_object()).pointer(); if_exprt size( dynamic_object(pointer), typecast_exprt(dynamic_size(ns), object_size(pointer).type()), object_size(pointer)); plus_exprt effective_offset(ode.offset(), pointer_offset(pointer)); assert(effective_offset.op0().type()==effective_offset.op1().type()); assert(effective_offset.type()==size.type()); binary_relation_exprt inequality(effective_offset, ID_lt, size); or_exprt precond( and_exprt( dynamic_object(pointer), not_exprt(malloc_object(pointer, ns))), inequality); add_guarded_claim( precond, name+" upper bound", "array bounds", expr.find_source_location(), expr, guard); return; } const exprt &size=array_type.id()==ID_array ? to_array_type(array_type).size() : to_vector_type(array_type).size(); if(size.is_nil()) { // Linking didn't complete, we don't have a size. // Not clear what to do. } else if(size.id()==ID_infinity) { } else if(size.is_zero() && expr.array().id()==ID_member) { // a variable sized struct member } else { binary_relation_exprt inequality(index, ID_lt, size); // typecast size if(inequality.op1().type()!=inequality.op0().type()) inequality.op1().make_typecast(inequality.op0().type()); // typecast size if(inequality.op1().type()!=inequality.op0().type()) inequality.op1().make_typecast(inequality.op0().type()); add_guarded_claim( inequality, name+" upper bound", "array bounds", expr.find_source_location(), expr, guard); } }
/// add axioms corresponding to the String.compareTo java function /// \par parameters: function application with two string arguments /// \return a integer expression exprt string_constraint_generatort::add_axioms_for_compare_to( const function_application_exprt &f) { string_exprt s1=add_axioms_for_string_expr(args(f, 2)[0]); string_exprt s2=add_axioms_for_string_expr(args(f, 2)[1]); const typet &return_type=f.type(); symbol_exprt res=fresh_symbol("compare_to", return_type); typet index_type=s1.length().type(); // In the lexicographic comparison, x is the first point where the two // strings differ. // We add axioms: // a1 : res==0 => |s1|=|s2| // a2 : forall i<|s1|. s1[i]==s2[i] // a3 : exists x. // res!=0 ==> x> 0 && // ((|s1| <= |s2| &&x<|s1|) || (|s1| >= |s2| &&x<|s2|) // &&res=s1[x]-s2[x] ) // || cond2: // (|s1|<|s2| &&x=|s1|) || (|s1| > |s2| &&x=|s2|) &&res=|s1|-|s2|) // a4 : forall i<x. res!=0 => s1[i]=s2[i] assert(return_type.id()==ID_signedbv); equal_exprt res_null=equal_exprt(res, from_integer(0, return_type)); implies_exprt a1(res_null, s1.axiom_for_has_same_length_as(s2)); axioms.push_back(a1); symbol_exprt i=fresh_univ_index("QA_compare_to", index_type); string_constraintt a2(i, s1.length(), res_null, equal_exprt(s1[i], s2[i])); axioms.push_back(a2); symbol_exprt x=fresh_exist_index("index_compare_to", index_type); equal_exprt ret_char_diff( res, minus_exprt( typecast_exprt(s1[x], return_type), typecast_exprt(s2[x], return_type))); equal_exprt ret_length_diff( res, minus_exprt( typecast_exprt(s1.length(), return_type), typecast_exprt(s2.length(), return_type))); or_exprt guard1( and_exprt(s1.axiom_for_is_shorter_than(s2), s1.axiom_for_is_strictly_longer_than(x)), and_exprt(s1.axiom_for_is_longer_than(s2), s2.axiom_for_is_strictly_longer_than(x))); and_exprt cond1(ret_char_diff, guard1); or_exprt guard2( and_exprt(s2.axiom_for_is_strictly_longer_than(s1), s1.axiom_for_has_length(x)), and_exprt(s1.axiom_for_is_strictly_longer_than(s2), s2.axiom_for_has_length(x))); and_exprt cond2(ret_length_diff, guard2); implies_exprt a3( not_exprt(res_null), and_exprt( binary_relation_exprt(x, ID_ge, from_integer(0, return_type)), or_exprt(cond1, cond2))); axioms.push_back(a3); string_constraintt a4(i, x, not_exprt(res_null), equal_exprt(s1[i], s2[i])); axioms.push_back(a4); return res; }
void symex_target_equationt::convert_assertions( prop_convt &prop_conv) { // we find out if there is only _one_ assertion, // which allows for a simpler formula unsigned number_of_assertions=count_assertions(); if(number_of_assertions==0) return; if(number_of_assertions==1) { for(auto & it : SSA_steps) { if(it.is_assert()) { prop_conv.set_to_false(it.cond_expr); it.cond_literal=const_literal(false); return; // prevent further assumptions! } else if(it.is_assume()) prop_conv.set_to_true(it.cond_expr); } assert(false); // unreachable } // We do (NOT a1) OR (NOT a2) ... // where the a's are the assertions or_exprt::operandst disjuncts; disjuncts.reserve(number_of_assertions); exprt assumption=true_exprt(); for(auto & it : SSA_steps) { if(it.is_assert()) { implies_exprt implication( assumption, it.cond_expr); // do the conversion it.cond_literal=prop_conv.convert(implication); // store disjunct disjuncts.push_back(literal_exprt(!it.cond_literal)); } else if(it.is_assume()) { // the assumptions have been converted before // avoid deep nesting of ID_and expressions if(assumption.id()==ID_and) assumption.copy_to_operands(literal_exprt(it.cond_literal)); else assumption= and_exprt(assumption, literal_exprt(it.cond_literal)); } } // the below is 'true' if there are no assertions prop_conv.set_to_true(disjunction(disjuncts)); }
bool disjunctive_polynomial_accelerationt::accelerate( path_acceleratort &accelerator) { std::map<exprt, polynomialt> polynomials; scratch_programt program(symbol_table); accelerator.clear(); #ifdef DEBUG std::cout << "Polynomial accelerating program:" << std::endl; for (goto_programt::instructionst::iterator it = goto_program.instructions.begin(); it != goto_program.instructions.end(); ++it) { if (loop.find(it) != loop.end()) { goto_program.output_instruction(ns, "scratch", std::cout, it); } } std::cout << "Modified:" << std::endl; for (expr_sett::iterator it = modified.begin(); it != modified.end(); ++it) { std::cout << expr2c(*it, ns) << std::endl; } #endif if (loop_counter.is_nil()) { symbolt loop_sym = utils.fresh_symbol("polynomial::loop_counter", unsigned_poly_type()); loop_counter = loop_sym.symbol_expr(); } patht &path = accelerator.path; path.clear(); if (!find_path(path)) { // No more paths! return false; } #if 0 for (expr_sett::iterator it = modified.begin(); it != modified.end(); ++it) { polynomialt poly; exprt target = *it; if (it->type().id() == ID_bool) { // Hack: don't try to accelerate booleans. continue; } if (target.id() == ID_index || target.id() == ID_dereference) { // We'll handle this later. continue; } if (fit_polynomial(target, poly, path)) { std::map<exprt, polynomialt> this_poly; this_poly[target] = poly; if (utils.check_inductive(this_poly, path)) { #ifdef DEBUG std::cout << "Fitted a polynomial for " << expr2c(target, ns) << std::endl; #endif polynomials[target] = poly; accelerator.changed_vars.insert(target); break; } } } if (polynomials.empty()) { return false; } #endif // Fit polynomials for the other variables. expr_sett dirty; utils.find_modified(accelerator.path, dirty); polynomial_acceleratort path_acceleration(symbol_table, goto_functions, loop_counter); goto_programt::instructionst assigns; for (patht::iterator it = accelerator.path.begin(); it != accelerator.path.end(); ++it) { if (it->loc->is_assign() || it->loc->is_decl()) { assigns.push_back(*(it->loc)); } } for (expr_sett::iterator it = dirty.begin(); it != dirty.end(); ++it) { #ifdef DEBUG std::cout << "Trying to accelerate " << expr2c(*it, ns) << std::endl; #endif if (it->type().id() == ID_bool) { // Hack: don't try to accelerate booleans. accelerator.dirty_vars.insert(*it); #ifdef DEBUG std::cout << "Ignoring boolean" << std::endl; #endif continue; } if (it->id() == ID_index || it->id() == ID_dereference) { #ifdef DEBUG std::cout << "Ignoring array reference" << std::endl; #endif continue; } if (accelerator.changed_vars.find(*it) != accelerator.changed_vars.end()) { // We've accelerated variable this already. #ifdef DEBUG std::cout << "We've accelerated it already" << std::endl; #endif continue; } // Hack: ignore variables that depend on array values.. exprt array_rhs; if (depends_on_array(*it, array_rhs)) { #ifdef DEBUG std::cout << "Ignoring because it depends on an array" << std::endl; #endif continue; } polynomialt poly; exprt target(*it); if (path_acceleration.fit_polynomial(assigns, target, poly)) { std::map<exprt, polynomialt> this_poly; this_poly[target] = poly; if (utils.check_inductive(this_poly, accelerator.path)) { polynomials[target] = poly; accelerator.changed_vars.insert(target); continue; } } #ifdef DEBUG std::cout << "Failed to accelerate " << expr2c(*it, ns) << std::endl; #endif // We weren't able to accelerate this target... accelerator.dirty_vars.insert(target); } /* if (!utils.check_inductive(polynomials, assigns)) { // They're not inductive :-( return false; } */ substitutiont stashed; utils.stash_polynomials(program, polynomials, stashed, path); exprt guard; bool path_is_monotone; try { path_is_monotone = utils.do_assumptions(polynomials, path, guard); } catch (std::string s) { // Couldn't do WP. std::cout << "Assumptions error: " << s << std::endl; return false; } exprt pre_guard(guard); for (std::map<exprt, polynomialt>::iterator it = polynomials.begin(); it != polynomials.end(); ++it) { replace_expr(it->first, it->second.to_expr(), guard); } if (path_is_monotone) { // OK cool -- the path is monotone, so we can just assume the condition for // the last iteration. replace_expr(loop_counter, minus_exprt(loop_counter, from_integer(1, loop_counter.type())), guard); } else { // The path is not monotone, so we need to introduce a quantifier to ensure // that the condition held for all 0 <= k < n. symbolt k_sym = utils.fresh_symbol("polynomial::k", unsigned_poly_type()); exprt k = k_sym.symbol_expr(); exprt k_bound = and_exprt(binary_relation_exprt(from_integer(0, k.type()), "<=", k), binary_relation_exprt(k, "<", loop_counter)); replace_expr(loop_counter, k, guard); simplify(guard, ns); implies_exprt implies(k_bound, guard); exprt forall(ID_forall); forall.type() = bool_typet(); forall.copy_to_operands(k); forall.copy_to_operands(implies); guard = forall; } // All our conditions are met -- we can finally build the accelerator! // It is of the form: // // loop_counter = *; // target1 = polynomial1; // target2 = polynomial2; // ... // assume(guard); // assume(no overflows in previous code); program.add_instruction(ASSUME)->guard = pre_guard; program.assign(loop_counter, side_effect_expr_nondett(loop_counter.type())); for (std::map<exprt, polynomialt>::iterator it = polynomials.begin(); it != polynomials.end(); ++it) { program.assign(it->first, it->second.to_expr()); accelerator.changed_vars.insert(it->first); } // Add in any array assignments we can do now. if (!utils.do_arrays(assigns, polynomials, loop_counter, stashed, program)) { // We couldn't model some of the array assignments with polynomials... // Unfortunately that means we just have to bail out. return false; } program.add_instruction(ASSUME)->guard = guard; program.fix_types(); if (path_is_monotone) { utils.ensure_no_overflows(program); } accelerator.pure_accelerator.instructions.swap(program.instructions); return true; }
void local_SSAt::assign_rec( const exprt &lhs, const exprt &rhs, const exprt &guard, locationt loc) { const typet &type=ns.follow(lhs.type()); if(is_symbol_struct_member(lhs, ns)) { if(type.id()==ID_struct) { // need to split up const struct_typet &struct_type=to_struct_type(type); const struct_typet::componentst &components=struct_type.components(); for(struct_typet::componentst::const_iterator it=components.begin(); it!=components.end(); it++) { member_exprt new_lhs(lhs, it->get_name(), it->type()); member_exprt new_rhs(rhs, it->get_name(), it->type()); assign_rec(new_lhs, new_rhs, guard, loc); } return; } ssa_objectt lhs_object(lhs, ns); const std::set<ssa_objectt> &assigned= assignments.get(loc); if(assigned.find(lhs_object)!=assigned.end()) { exprt ssa_rhs=read_rhs(rhs, loc); const symbol_exprt ssa_symbol=name(lhs_object, OUT, loc); equal_exprt equality(ssa_symbol, ssa_rhs); nodes[loc].equalities.push_back(equality); } } else if(lhs.id()==ID_index) { const index_exprt &index_expr=to_index_expr(lhs); exprt ssa_array=index_expr.array(); exprt new_rhs=with_exprt(ssa_array, index_expr.index(), rhs); assign_rec(index_expr.array(), new_rhs, guard, loc); } else if(lhs.id()==ID_member) { // These are non-flattened struct or union members. const member_exprt &member_expr=to_member_expr(lhs); const exprt &compound=member_expr.struct_op(); const typet &compound_type=ns.follow(compound.type()); if(compound_type.id()==ID_union) { union_exprt new_rhs(member_expr.get_component_name(), rhs, compound.type()); assign_rec(member_expr.struct_op(), new_rhs, guard, loc); } else if(compound_type.id()==ID_struct) { exprt member_name(ID_member_name); member_name.set(ID_component_name, member_expr.get_component_name()); with_exprt new_rhs(compound, member_name, rhs); assign_rec(compound, new_rhs, guard, loc); } } else if(lhs.id()==ID_complex_real) { assert(lhs.operands().size()==1); const exprt &op=lhs.op0(); const complex_typet &complex_type=to_complex_type(op.type()); exprt imag_op=unary_exprt(ID_complex_imag, op, complex_type.subtype()); complex_exprt new_rhs(rhs, imag_op, complex_type); assign_rec(op, new_rhs, guard, loc); } else if(lhs.id()==ID_complex_imag) { assert(lhs.operands().size()==1); const exprt &op=lhs.op0(); const complex_typet &complex_type=to_complex_type(op.type()); exprt real_op=unary_exprt(ID_complex_real, op, complex_type.subtype()); complex_exprt new_rhs(real_op, rhs, complex_type); assign_rec(op, new_rhs, guard, loc); } else if(lhs.id()==ID_if) { const if_exprt &if_expr=to_if_expr(lhs); assign_rec(if_expr.true_case(), rhs, and_exprt(guard, if_expr.cond()), loc); assign_rec(if_expr.false_case(), rhs, and_exprt(guard, not_exprt(if_expr.cond())), loc); } else if(lhs.id()==ID_byte_extract_little_endian || lhs.id()==ID_byte_extract_big_endian) { const byte_extract_exprt &byte_extract_expr=to_byte_extract_expr(lhs); exprt new_lhs=byte_extract_expr.op(); exprt new_rhs=byte_extract_exprt( byte_extract_expr.id(), rhs, byte_extract_expr.offset(), new_lhs.type()); assign_rec(new_lhs, new_rhs, guard, loc); } else throw "UNKNOWN LHS: "+lhs.id_string(); }
void goto_checkt::conversion_check( const exprt &expr, const guardt &guard) { if(!enable_conversion_check) return; // First, check type. const typet &type=ns.follow(expr.type()); if(type.id()!=ID_signedbv && type.id()!=ID_unsignedbv) return; if(expr.id()==ID_typecast) { // conversion to signed int may overflow if(expr.operands().size()!=1) throw "typecast takes one operand"; const typet &old_type=ns.follow(expr.op0().type()); if(type.id()==ID_signedbv) { std::size_t new_width=to_signedbv_type(type).get_width(); if(old_type.id()==ID_signedbv) // signed -> signed { std::size_t old_width=to_signedbv_type(old_type).get_width(); if(new_width>=old_width) return; // always ok binary_relation_exprt no_overflow_upper(ID_le); no_overflow_upper.lhs()=expr.op0(); no_overflow_upper.rhs()=from_integer(power(2, new_width-1)-1, old_type); binary_relation_exprt no_overflow_lower(ID_ge); no_overflow_lower.lhs()=expr.op0(); no_overflow_lower.rhs()=from_integer(-power(2, new_width-1), old_type); add_guarded_claim( and_exprt(no_overflow_lower, no_overflow_upper), "arithmetic overflow on signed type conversion", "overflow", expr.find_source_location(), expr, guard); } else if(old_type.id()==ID_unsignedbv) // unsigned -> signed { std::size_t old_width=to_unsignedbv_type(old_type).get_width(); if(new_width>=old_width+1) return; // always ok binary_relation_exprt no_overflow_upper(ID_le); no_overflow_upper.lhs()=expr.op0(); no_overflow_upper.rhs()=from_integer(power(2, new_width-1)-1, old_type); add_guarded_claim( no_overflow_upper, "arithmetic overflow on unsigned to signed type conversion", "overflow", expr.find_source_location(), expr, guard); } else if(old_type.id()==ID_floatbv) // float -> signed { // Note that the fractional part is truncated! ieee_floatt upper(to_floatbv_type(old_type)); upper.from_integer(power(2, new_width-1)); binary_relation_exprt no_overflow_upper(ID_lt); no_overflow_upper.lhs()=expr.op0(); no_overflow_upper.rhs()=upper.to_expr(); ieee_floatt lower(to_floatbv_type(old_type)); lower.from_integer(-power(2, new_width-1)-1); binary_relation_exprt no_overflow_lower(ID_gt); no_overflow_lower.lhs()=expr.op0(); no_overflow_lower.rhs()=lower.to_expr(); add_guarded_claim( and_exprt(no_overflow_lower, no_overflow_upper), "arithmetic overflow on float to signed integer type conversion", "overflow", expr.find_source_location(), expr, guard); } } else if(type.id()==ID_unsignedbv) { std::size_t new_width=to_unsignedbv_type(type).get_width(); if(old_type.id()==ID_signedbv) // signed -> unsigned { std::size_t old_width=to_signedbv_type(old_type).get_width(); if(new_width>=old_width-1) { // only need lower bound check binary_relation_exprt no_overflow_lower(ID_ge); no_overflow_lower.lhs()=expr.op0(); no_overflow_lower.rhs()=from_integer(0, old_type); add_guarded_claim( no_overflow_lower, "arithmetic overflow on signed to unsigned type conversion", "overflow", expr.find_source_location(), expr, guard); } else { // need both binary_relation_exprt no_overflow_upper(ID_le); no_overflow_upper.lhs()=expr.op0(); no_overflow_upper.rhs()=from_integer(power(2, new_width)-1, old_type); binary_relation_exprt no_overflow_lower(ID_ge); no_overflow_lower.lhs()=expr.op0(); no_overflow_lower.rhs()=from_integer(0, old_type); add_guarded_claim( and_exprt(no_overflow_lower, no_overflow_upper), "arithmetic overflow on signed to unsigned type conversion", "overflow", expr.find_source_location(), expr, guard); } } else if(old_type.id()==ID_unsignedbv) // unsigned -> unsigned { std::size_t old_width=to_unsignedbv_type(old_type).get_width(); if(new_width>=old_width) return; // always ok binary_relation_exprt no_overflow_upper(ID_le); no_overflow_upper.lhs()=expr.op0(); no_overflow_upper.rhs()=from_integer(power(2, new_width)-1, old_type); add_guarded_claim( no_overflow_upper, "arithmetic overflow on unsigned to unsigned type conversion", "overflow", expr.find_source_location(), expr, guard); } else if(old_type.id()==ID_floatbv) // float -> unsigned { // Note that the fractional part is truncated! ieee_floatt upper(to_floatbv_type(old_type)); upper.from_integer(power(2, new_width)-1); binary_relation_exprt no_overflow_upper(ID_lt); no_overflow_upper.lhs()=expr.op0(); no_overflow_upper.rhs()=upper.to_expr(); ieee_floatt lower(to_floatbv_type(old_type)); lower.from_integer(-1); binary_relation_exprt no_overflow_lower(ID_gt); no_overflow_lower.lhs()=expr.op0(); no_overflow_lower.rhs()=lower.to_expr(); add_guarded_claim( and_exprt(no_overflow_lower, no_overflow_upper), "arithmetic overflow on float to unsigned integer type conversion", "overflow", expr.find_source_location(), expr, guard); } } } }
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); }
void goto_checkt::integer_overflow_check( const exprt &expr, const guardt &guard) { if(!enable_signed_overflow_check && !enable_unsigned_overflow_check) return; // First, check type. const typet &type=ns.follow(expr.type()); if(type.id()==ID_signedbv && !enable_signed_overflow_check) return; if(type.id()==ID_unsignedbv && !enable_unsigned_overflow_check) return; // add overflow subgoal if(expr.id()==ID_div) { assert(expr.operands().size()==2); // undefined for signed division INT_MIN/-1 if(type.id()==ID_signedbv) { equal_exprt int_min_eq( expr.op0(), to_signedbv_type(type).smallest_expr()); equal_exprt minus_one_eq( expr.op1(), from_integer(-1, type)); add_guarded_claim( not_exprt(and_exprt(int_min_eq, minus_one_eq)), "arithmetic overflow on signed division", "overflow", expr.find_source_location(), expr, guard); } return; } else if(expr.id()==ID_mod) { // these can't overflow return; } else if(expr.id()==ID_unary_minus) { if(type.id()==ID_signedbv) { // overflow on unary- can only happen with the smallest // representable number 100....0 equal_exprt int_min_eq( expr.op0(), to_signedbv_type(type).smallest_expr()); add_guarded_claim( not_exprt(int_min_eq), "arithmetic overflow on signed unary minus", "overflow", expr.find_source_location(), expr, guard); } return; } exprt overflow("overflow-"+expr.id_string(), bool_typet()); overflow.operands()=expr.operands(); if(expr.operands().size()>=3) { // The overflow checks are binary! // We break these up. for(unsigned i=1; i<expr.operands().size(); i++) { exprt tmp; if(i==1) tmp=expr.op0(); else { tmp=expr; tmp.operands().resize(i); } overflow.operands().resize(2); overflow.op0()=tmp; overflow.op1()=expr.operands()[i]; std::string kind= type.id()==ID_unsignedbv?"unsigned":"signed"; add_guarded_claim( not_exprt(overflow), "arithmetic overflow on "+kind+" "+expr.id_string(), "overflow", expr.find_source_location(), expr, guard); } } else { std::string kind= type.id()==ID_unsignedbv?"unsigned":"signed"; add_guarded_claim( not_exprt(overflow), "arithmetic overflow on "+kind+" "+expr.id_string(), "overflow", expr.find_source_location(), expr, guard); } }
void goto_checkt::nan_check( const exprt &expr, const guardt &guard) { if(!enable_nan_check) return; // first, check type if(expr.type().id()!=ID_floatbv) return; if(expr.id()!=ID_plus && expr.id()!=ID_mult && expr.id()!=ID_div && expr.id()!=ID_minus) return; // add NaN subgoal exprt isnan; if(expr.id()==ID_div) { assert(expr.operands().size()==2); // there a two ways to get a new NaN on division: // 0/0 = NaN and x/inf = NaN // (note that x/0 = +-inf for x!=0 and x!=inf) exprt zero_div_zero=and_exprt( ieee_float_equal_exprt(expr.op0(), gen_zero(expr.op0().type())), ieee_float_equal_exprt(expr.op1(), gen_zero(expr.op1().type()))); exprt div_inf=unary_exprt(ID_isinf, expr.op1(), bool_typet()); isnan=or_exprt(zero_div_zero, div_inf); } else if(expr.id()==ID_mult) { if(expr.operands().size()>=3) return nan_check(make_binary(expr), guard); assert(expr.operands().size()==2); // Inf * 0 is NaN exprt inf_times_zero=and_exprt( unary_exprt(ID_isinf, expr.op0(), bool_typet()), ieee_float_equal_exprt(expr.op1(), gen_zero(expr.op1().type()))); exprt zero_times_inf=and_exprt( ieee_float_equal_exprt(expr.op1(), gen_zero(expr.op1().type())), unary_exprt(ID_isinf, expr.op0(), bool_typet())); isnan=or_exprt(inf_times_zero, zero_times_inf); } else if(expr.id()==ID_plus) { if(expr.operands().size()>=3) return nan_check(make_binary(expr), guard); assert(expr.operands().size()==2); // -inf + +inf = NaN and +inf + -inf = NaN, // i.e., signs differ ieee_float_spect spec=ieee_float_spect(to_floatbv_type(expr.type())); exprt plus_inf=ieee_floatt::plus_infinity(spec).to_expr(); exprt minus_inf=ieee_floatt::minus_infinity(spec).to_expr(); isnan=or_exprt( and_exprt(equal_exprt(expr.op0(), minus_inf), equal_exprt(expr.op1(), plus_inf)), and_exprt(equal_exprt(expr.op0(), plus_inf), equal_exprt(expr.op1(), minus_inf))); } else if(expr.id()==ID_minus) { assert(expr.operands().size()==2); // +inf - +inf = NaN and -inf - -inf = NaN, // i.e., signs match ieee_float_spect spec=ieee_float_spect(to_floatbv_type(expr.type())); exprt plus_inf=ieee_floatt::plus_infinity(spec).to_expr(); exprt minus_inf=ieee_floatt::minus_infinity(spec).to_expr(); isnan=or_exprt( and_exprt(equal_exprt(expr.op0(), plus_inf), equal_exprt(expr.op1(), plus_inf)), and_exprt(equal_exprt(expr.op0(), minus_inf), equal_exprt(expr.op1(), minus_inf))); } else assert(false); isnan.make_not(); add_guarded_claim( isnan, "NaN on "+expr.id_string(), "NaN", expr.find_source_location(), expr, guard); }