/// 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]; }
/// 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]; }
/// returns an expression which is true when the two given characters are equal /// when ignoring case for ASCII /// \par parameters: two character expressions and constant character /// expressions /// representing 'a', 'A' and 'Z' /// \return a expression of Boolean type exprt string_constraint_generatort::character_equals_ignore_case( exprt char1, exprt char2, exprt char_a, exprt char_A, exprt char_Z) { and_exprt is_upper_case_1( binary_relation_exprt(char_A, ID_le, char1), binary_relation_exprt(char1, ID_le, char_Z)); and_exprt is_upper_case_2( binary_relation_exprt(char_A, ID_le, char2), binary_relation_exprt(char2, ID_le, char_Z)); // Three possibilities: // p1 : char1=char2 // p2 : (is_up1&&'a'-'A'+char1=char2) // p3 : (is_up2&&'a'-'A'+char2=char1) equal_exprt p1(char1, char2); minus_exprt diff=minus_exprt(char_a, char_A); and_exprt p2(is_upper_case_1, equal_exprt(plus_exprt(diff, char1), char2)); and_exprt p3(is_upper_case_2, equal_exprt(plus_exprt(diff, char2), char1)); return or_exprt(or_exprt(p1, p2), p3); }
/// 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; }
guardt &operator |= (guardt &g1, const guardt &g2) { if(g2.is_false()) return g1; if(g1.is_false()) { g1.guard_list=g2.guard_list; return g1; } // find common prefix guardt::guard_listt::iterator it1=g1.guard_list.begin(); guardt::guard_listt::const_iterator it2=g2.guard_list.begin(); while(it1!=g1.guard_list.end()) { if(it2==g2.guard_list.end()) break; if(*it1!=*it2) break; it1++; it2++; } if(it2==g2.guard_list.end()) return g1; // end of common prefix exprt and_expr1, and_expr2; and_expr1=g1.as_expr(it1); and_expr2=g2.as_expr(it2); g1.guard_list.erase(it1, g1.guard_list.end()); exprt tmp(and_expr2); tmp.make_not(); if(tmp!=and_expr1) { if(and_expr1.is_true() || and_expr2.is_true()) { } else g1.add(or_exprt(and_expr1, and_expr2)); } return g1; }
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); }
/// add axioms stating that the result is true exactly when the strings /// represented by the arguments are equal /// \par parameters: function application with two string arguments /// \return a expression of Boolean type exprt string_constraint_generatort::add_axioms_for_equals( const function_application_exprt &f) { assert(f.type()==bool_typet() || f.type().id()==ID_c_bool); symbol_exprt eq=fresh_boolean("equal"); 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 index_type=s1.length().type(); // We want to write: // eq <=> (s1.length=s2.length &&forall i<s1.length. s1[i]=s2[i]) // We add axioms: // a1 : eq => s1.length=s2.length // a2 : forall i<s1.length. eq => s1[i]=s2[i] // a3 : !eq => s1.length!=s2.length // || (witness<s1.length &&s1[witness]!=s2[witness]) implies_exprt a1(eq, s1.axiom_for_has_same_length_as(s2)); axioms.push_back(a1); symbol_exprt qvar=fresh_univ_index("QA_equal", index_type); string_constraintt a2(qvar, s1.length(), eq, equal_exprt(s1[qvar], s2[qvar])); axioms.push_back(a2); symbol_exprt witness=fresh_exist_index("witness_unequal", index_type); exprt zero=from_integer(0, index_type); and_exprt bound_witness( binary_relation_exprt(witness, ID_lt, s1.length()), binary_relation_exprt(witness, ID_ge, zero)); and_exprt witnessing(bound_witness, notequal_exprt(s1[witness], s2[witness])); implies_exprt a3( not_exprt(eq), or_exprt(notequal_exprt(s1.length(), s2.length()), witnessing)); axioms.push_back(a3); return tc_eq; }
/// 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; }
codet java_bytecode_convertt::convert_instructions( const instructionst &instructions, const code_typet &method_type) { // Run a worklist algorithm, assuming that the bytecode has not // been tampered with. See "Leroy, X. (2003). Java bytecode // verification: algorithms and formalizations. Journal of Automated // Reasoning, 30(3-4), 235-269." for a more complete treatment. // first pass: get targets and map addresses to instructions struct converted_instructiont { converted_instructiont( const instructionst::const_iterator &it, const codet &_code):source(it), code(_code), done(false) { } instructionst::const_iterator source; std::list<unsigned> successors; std::set<unsigned> predecessors; codet code; stackt stack; bool done; }; typedef std::map<unsigned, converted_instructiont> address_mapt; address_mapt address_map; std::set<unsigned> targets; for(instructionst::const_iterator i_it=instructions.begin(); i_it!=instructions.end(); i_it++) { std::pair<address_mapt::iterator, bool> a_entry= address_map.insert(std::make_pair( i_it->address, converted_instructiont(i_it, code_skipt()))); assert(a_entry.second); // addresses are strictly increasing, hence we must have inserted // a new maximal key assert(a_entry.first==--address_map.end()); if(i_it->statement!="goto" && i_it->statement!="return" && !(i_it->statement==patternt("?return")) && i_it->statement!="athrow") { instructionst::const_iterator next=i_it; if(++next!=instructions.end()) a_entry.first->second.successors.push_back(next->address); } if(i_it->statement=="goto" || i_it->statement==patternt("if_?cmp??") || i_it->statement==patternt("if??") || i_it->statement=="ifnonnull" || i_it->statement=="ifnull") { assert(!i_it->args.empty()); const unsigned target=safe_string2unsigned( id2string(to_constant_expr(i_it->args[0]).get_value())); targets.insert(target); a_entry.first->second.successors.push_back(target); } else if(i_it->statement=="tableswitch" || i_it->statement=="lookupswitch") { bool is_label=true; for(instructiont::argst::const_iterator a_it=i_it->args.begin(); a_it!=i_it->args.end(); a_it++, is_label=!is_label) { if(is_label) { const unsigned target=safe_string2unsigned( id2string(to_constant_expr(*a_it).get_value())); targets.insert(target); a_entry.first->second.successors.push_back(target); } } } } for(address_mapt::iterator it=address_map.begin(); it!=address_map.end(); ++it) { for(unsigned s : it->second.successors) { address_mapt::iterator a_it=address_map.find(s); assert(a_it!=address_map.end()); a_it->second.predecessors.insert(it->first); } } std::set<unsigned> working_set; if(!instructions.empty()) working_set.insert(instructions.front().address); while(!working_set.empty()) { std::set<unsigned>::iterator cur=working_set.begin(); address_mapt::iterator a_it=address_map.find(*cur); assert(a_it!=address_map.end()); working_set.erase(cur); if(a_it->second.done) continue; working_set.insert(a_it->second.successors.begin(), a_it->second.successors.end()); instructionst::const_iterator i_it=a_it->second.source; stack.swap(a_it->second.stack); a_it->second.stack.clear(); codet &c=a_it->second.code; assert(stack.empty() || a_it->second.predecessors.size()<=1 || has_prefix(stack.front().get_string(ID_C_base_name), "$stack")); irep_idt statement=i_it->statement; exprt arg0=i_it->args.size()>=1?i_it->args[0]:nil_exprt(); exprt arg1=i_it->args.size()>=2?i_it->args[1]:nil_exprt(); const bytecode_infot &bytecode_info=get_bytecode_info(statement); // deal with _idx suffixes if(statement.size()>=2 && statement[statement.size()-2]=='_' && isdigit(statement[statement.size()-1])) { arg0=constant_exprt( std::string(id2string(statement), statement.size()-1, 1), integer_typet()); statement=std::string(id2string(statement), 0, statement.size()-2); } exprt::operandst op=pop(bytecode_info.pop); exprt::operandst results; results.resize(bytecode_info.push, nil_exprt()); if(statement=="aconst_null") { assert(results.size()==1); results[0]=gen_zero(java_reference_type(void_typet())); } else if(statement=="athrow") { assert(op.size()==1 && results.size()==1); side_effect_expr_throwt throw_expr; throw_expr.add_source_location()=i_it->source_location; throw_expr.copy_to_operands(op[0]); c=code_expressiont(throw_expr); results[0]=op[0]; } else if(statement=="checkcast") { // checkcast throws an exception in case a cast of object // on stack to given type fails. // The stack isn't modified. assert(op.size()==1 && results.size()==1); results[0]=op[0]; } else if(statement=="invokedynamic") { // not used in Java code_typet &code_type=to_code_type(arg0.type()); const code_typet::parameterst ¶meters(code_type.parameters()); pop(parameters.size()); const typet &return_type=code_type.return_type(); if(return_type.id()!=ID_empty) { results.resize(1); results[0]=nil_exprt(); } } else if(statement=="invokeinterface" || statement=="invokespecial" || statement=="invokevirtual" || statement=="invokestatic") { const bool use_this(statement != "invokestatic"); const bool is_virtual( statement == "invokevirtual" || statement == "invokeinterface"); code_typet &code_type=to_code_type(arg0.type()); code_typet::parameterst ¶meters(code_type.parameters()); if(use_this) { if(parameters.empty() || !parameters[0].get_this()) { const empty_typet empty; pointer_typet object_ref_type(empty); code_typet::parametert this_p(object_ref_type); this_p.set_this(); this_p.set_base_name("this"); parameters.insert(parameters.begin(), this_p); } } code_function_callt call; call.add_source_location()=i_it->source_location; call.arguments() = pop(parameters.size()); // double-check a bit if(use_this) { const exprt &this_arg=call.arguments().front(); assert(this_arg.type().id()==ID_pointer); } // do some type adjustment for the arguments, // as Java promotes arguments for(unsigned i=0; i<parameters.size(); i++) { const typet &type=parameters[i].type(); if(type==java_boolean_type() || type==java_char_type() || type==java_byte_type() || type==java_short_type()) { assert(i<call.arguments().size()); call.arguments()[i].make_typecast(type); } } // do some type adjustment for return values const typet &return_type=code_type.return_type(); if(return_type.id()!=ID_empty) { // return types are promoted in Java call.lhs()=tmp_variable("return", return_type); exprt promoted=java_bytecode_promotion(call.lhs()); results.resize(1); results[0]=promoted; } assert(arg0.id()==ID_virtual_function); // does the function symbol exist? irep_idt id=arg0.get(ID_identifier); if(symbol_table.symbols.find(id)==symbol_table.symbols.end()) { // no, create stub symbolt symbol; symbol.name=id; symbol.base_name=arg0.get(ID_C_base_name); symbol.type=arg0.type(); symbol.value.make_nil(); symbol.mode=ID_java; symbol_table.add(symbol); } if(is_virtual) { // dynamic binding assert(use_this); assert(!call.arguments().empty()); call.function()=arg0; } else { // static binding /*if(id == "java::java.lang.String.charAt:(I)C") call.function()=symbol_exprt("java::__CPROVER_uninterpreted_char_at", arg0.type()); else*/ call.function()=symbol_exprt(arg0.get(ID_identifier), arg0.type()); } call.function().add_source_location()=i_it->source_location; c = call; } else if(statement=="return") { assert(op.empty() && results.empty()); c=code_returnt(); } else if(statement==patternt("?return")) { // Return types are promoted in java, so this might need // conversion. assert(op.size()==1 && results.empty()); exprt r=op[0]; if(r.type()!=method_return_type) r=typecast_exprt(r, method_return_type); c=code_returnt(r); } else if(statement==patternt("?astore")) { assert(op.size()==3 && results.empty()); char type_char=statement[0]; exprt pointer= typecast_exprt(op[0], java_array_type(type_char)); const dereference_exprt deref(pointer, pointer.type().subtype()); const member_exprt data_ptr( deref, "data", pointer_typet(java_type_from_char(type_char))); plus_exprt data_plus_offset(data_ptr, op[1], data_ptr.type()); typet element_type=data_ptr.type().subtype(); const dereference_exprt element(data_plus_offset, element_type); c=code_assignt(element, op[2]); } else if(statement==patternt("?store")) { // store value into some local variable assert(op.size()==1 && results.empty()); exprt var=variable(arg0, statement[0]); const bool is_array('a' == statement[0]); if(is_array) var.type()=op[0].type(); c=code_assignt(var, op[0]); } else if(statement==patternt("?aload")) { assert(op.size() == 2 && results.size() == 1); char type_char=statement[0]; exprt pointer= typecast_exprt(op[0], java_array_type(type_char)); const dereference_exprt deref(pointer, pointer.type().subtype()); const member_exprt data_ptr( deref, "data", pointer_typet(java_type_from_char(type_char))); plus_exprt data_plus_offset(data_ptr, op[1], data_ptr.type()); typet element_type=data_ptr.type().subtype(); dereference_exprt element(data_plus_offset, element_type); results[0]=java_bytecode_promotion(element); } else if(statement==patternt("?load")) { // load a value from a local variable results[0]=variable(arg0, statement[0]); } else if(statement=="ldc" || statement=="ldc_w" || statement=="ldc2" || statement=="ldc2_w") { assert(op.empty() && results.size()==1); // 1) Pushing a String causes a reference to a java.lang.String object // to be constructed and pushed onto the operand stack. // 2) Pushing an int or a float causes a primitive value to be pushed // onto the stack. // 3) Pushing a Class constant causes a reference to a java.lang.Class // to be pushed onto the operand stack if(arg0.id()==ID_java_string_literal) { // these need to be references to java.lang.String results[0]=arg0; symbol_typet string_type("java::java.lang.String"); results[0].type()=pointer_typet(string_type); } else if(arg0.id()==ID_type) { irep_idt class_id=arg0.type().get(ID_identifier); symbol_typet java_lang_Class("java::java.lang.Class"); symbol_exprt symbol_expr(id2string(class_id)+"@class_model", java_lang_Class); address_of_exprt address_of_expr(symbol_expr); results[0]=address_of_expr; } else if(arg0.id()==ID_constant) { results[0]=arg0; } else { error() << "unexpected ldc argument" << eom; throw 0; } } else if(statement=="goto" || statement=="goto_w") { assert(op.empty() && results.empty()); irep_idt number=to_constant_expr(arg0).get_value(); code_gotot code_goto(label(number)); c=code_goto; } else if(statement=="iconst_m1") { assert(results.size()==1); results[0]=from_integer(-1, java_int_type()); } else if(statement==patternt("?const")) { assert(results.size() == 1); const char type_char=statement[0]; const bool is_double('d' == type_char); const bool is_float('f' == type_char); if(is_double || is_float) { const ieee_float_spect spec( is_float ? ieee_float_spect::single_precision() : ieee_float_spect::double_precision()); ieee_floatt value(spec); const typet &arg_type(arg0.type()); if(ID_integer == arg_type.id()) value.from_integer(arg0.get_int(ID_value)); else value.from_expr(to_constant_expr(arg0)); results[0] = value.to_expr(); } else { const unsigned int value(arg0.get_unsigned_int(ID_value)); const typet type=java_type_from_char(statement[0]); results[0] = as_number(value, type); } } else if(statement==patternt("?ipush")) { assert(results.size()==1); results[0]=typecast_exprt(arg0, java_int_type()); } else if(statement==patternt("if_?cmp??")) { irep_idt number=to_constant_expr(arg0).get_value(); assert(op.size()==2 && results.empty()); code_ifthenelset code_branch; const irep_idt cmp_op=get_if_cmp_operator(statement); binary_relation_exprt condition(op[0], cmp_op, op[1]); cast_if_necessary(condition); code_branch.cond()=condition; code_branch.then_case()=code_gotot(label(number)); code_branch.then_case().add_source_location()=i_it->source_location; code_branch.add_source_location()=i_it->source_location; c=code_branch; } else if(statement==patternt("if??")) { const irep_idt id= statement=="ifeq"?ID_equal: statement=="ifne"?ID_notequal: statement=="iflt"?ID_lt: statement=="ifge"?ID_ge: statement=="ifgt"?ID_gt: statement=="ifle"?ID_le: (assert(false), ""); irep_idt number=to_constant_expr(arg0).get_value(); assert(op.size()==1 && results.empty()); code_ifthenelset code_branch; code_branch.cond()=binary_relation_exprt(op[0], id, gen_zero(op[0].type())); code_branch.cond().add_source_location()=i_it->source_location; code_branch.then_case()=code_gotot(label(number)); code_branch.then_case().add_source_location()=i_it->source_location; code_branch.add_source_location()=i_it->source_location; c=code_branch; } else if(statement==patternt("ifnonnull")) { irep_idt number=to_constant_expr(arg0).get_value(); assert(op.size()==1 && results.empty()); code_ifthenelset code_branch; const typecast_exprt lhs(op[0], pointer_typet()); const exprt rhs(gen_zero(lhs.type())); code_branch.cond()=binary_relation_exprt(lhs, ID_notequal, rhs); code_branch.then_case()=code_gotot(label(number)); code_branch.then_case().add_source_location()=i_it->source_location; code_branch.add_source_location()=i_it->source_location; c=code_branch; } else if(statement==patternt("ifnull")) { assert(op.size()==1 && results.empty()); irep_idt number=to_constant_expr(arg0).get_value(); code_ifthenelset code_branch; const typecast_exprt lhs(op[0], pointer_typet(empty_typet())); const exprt rhs(gen_zero(lhs.type())); code_branch.cond()=binary_relation_exprt(lhs, ID_equal, rhs); code_branch.then_case()=code_gotot(label(number)); code_branch.then_case().add_source_location()=i_it->source_location; code_branch.add_source_location()=i_it->source_location; c=code_branch; } else if(statement=="iinc") { code_assignt code_assign; code_assign.lhs()=variable(arg0, 'i'); code_assign.rhs()=plus_exprt( variable(arg0, 'i'), typecast_exprt(arg1, java_int_type())); c=code_assign; } else if(statement==patternt("?xor")) { assert(op.size()==2 && results.size()==1); results[0]=bitxor_exprt(op[0], op[1]); } else if(statement==patternt("?or")) { assert(op.size()==2 && results.size()==1); results[0]=bitor_exprt(op[0], op[1]); } else if(statement==patternt("?and")) { assert(op.size()==2 && results.size()==1); results[0]=bitand_exprt(op[0], op[1]); } else if(statement==patternt("?shl")) { assert(op.size()==2 && results.size()==1); results[0]=shl_exprt(op[0], op[1]); } else if(statement==patternt("?shr")) { assert(op.size()==2 && results.size()==1); results[0]=ashr_exprt(op[0], op[1]); } else if(statement==patternt("?ushr")) { assert(op.size()==2 && results.size()==1); const typet type(java_type_from_char(statement[0])); const unsigned int width(type.get_unsigned_int(ID_width)); typet target=unsigned_long_int_type(); target.set(ID_width, width); const typecast_exprt lhs(op[0], target); const typecast_exprt rhs(op[1], target); results[0]=lshr_exprt(lhs, rhs); } else if(statement==patternt("?add")) { assert(op.size()==2 && results.size()==1); results[0]=plus_exprt(op[0], op[1]); } else if(statement==patternt("?sub")) { assert(op.size()==2 && results.size()==1); results[0]=minus_exprt(op[0], op[1]); } else if(statement==patternt("?div")) { assert(op.size()==2 && results.size()==1); results[0]=div_exprt(op[0], op[1]); } else if(statement==patternt("?mul")) { assert(op.size()==2 && results.size()==1); results[0]=mult_exprt(op[0], op[1]); } else if(statement==patternt("?neg")) { assert(op.size()==1 && results.size()==1); results[0]=unary_minus_exprt(op[0], op[0].type()); } else if(statement==patternt("?rem")) { assert(op.size()==2 && results.size()==1); if(statement=="frem" || statement=="drem") results[0]=rem_exprt(op[0], op[1]); else results[0]=mod_exprt(op[0], op[1]); } else if(statement==patternt("?cmp")) { assert(op.size() == 2 && results.size() == 1); // The integer result on the stack is: // 0 if op[0] equals op[1] // -1 if op[0] is less than op[1] // 1 if op[0] is greater than op[1] const typet t=java_int_type(); results[0]= if_exprt(binary_relation_exprt(op[0], ID_equal, op[1]), gen_zero(t), if_exprt(binary_relation_exprt(op[0], ID_gt, op[1]), from_integer(1, t), from_integer(-1, t))); } else if(statement==patternt("?cmp?")) { assert(op.size()==2 && results.size()==1); const floatbv_typet type(to_floatbv_type(java_type_from_char(statement[0]))); const ieee_float_spect spec(type); const ieee_floatt nan(ieee_floatt::NaN(spec)); const constant_exprt nan_expr(nan.to_expr()); const int nan_value(statement[4] == 'l' ? -1 : 1); const typet result_type(java_int_type()); const exprt nan_result(from_integer(nan_value, result_type)); // (value1 == NaN || value2 == NaN) ? nan_value : value1 < value2 ? -1 : value2 < value1 1 ? 1 : 0; // (value1 == NaN || value2 == NaN) ? nan_value : value1 == value2 ? 0 : value1 < value2 -1 ? 1 : 0; results[0]= if_exprt(or_exprt(ieee_float_equal_exprt(nan_expr, op[0]), ieee_float_equal_exprt(nan_expr, op[1])), nan_result, if_exprt(ieee_float_equal_exprt(op[0], op[1]), gen_zero(result_type), if_exprt(binary_relation_exprt(op[0], ID_lt, op[1]), from_integer(-1, result_type), from_integer(1, result_type)))); } else if(statement==patternt("?cmpl")) { assert(op.size()==2 && results.size()==1); results[0]=binary_relation_exprt(op[0], ID_lt, op[1]); } else if(statement=="dup") { assert(op.size()==1 && results.size()==2); results[0]=results[1]=op[0]; } else if(statement=="dup_x1") { assert(op.size()==2 && results.size()==3); results[0]=op[1]; results[1]=op[0]; results[2]=op[1]; } else if(statement=="dup_x2") { assert(op.size()==3 && results.size()==4); results[0]=op[2]; results[1]=op[0]; results[2]=op[1]; results[3]=op[2]; } // dup2* behaviour depends on the size of the operands on the // stack else if(statement=="dup2") { assert(!stack.empty() && results.empty()); if(stack.back().type().get_unsigned_int(ID_width)==32) op=pop(2); else op=pop(1); results.insert(results.end(), op.begin(), op.end()); results.insert(results.end(), op.begin(), op.end()); } else if(statement=="dup2_x1") { assert(!stack.empty() && results.empty()); if(stack.back().type().get_unsigned_int(ID_width)==32) op=pop(3); else op=pop(2); results.insert(results.end(), op.begin()+1, op.end()); results.insert(results.end(), op.begin(), op.end()); } else if(statement=="dup2_x2") { assert(!stack.empty() && results.empty()); if(stack.back().type().get_unsigned_int(ID_width)==32) op=pop(2); else op=pop(1); assert(!stack.empty()); exprt::operandst op2; if(stack.back().type().get_unsigned_int(ID_width)==32) op2=pop(2); else op2=pop(1); results.insert(results.end(), op.begin(), op.end()); results.insert(results.end(), op2.begin(), op2.end()); results.insert(results.end(), op.begin(), op.end()); } else if(statement=="dconst") { assert(op.empty() && results.size()==1); } else if(statement=="fconst") { assert(op.empty() && results.size()==1); } else if(statement=="getfield") { assert(op.size()==1 && results.size()==1); results[0]=to_member(op[0], arg0); } else if(statement=="getstatic") { assert(op.empty() && results.size()==1); symbol_exprt symbol_expr(arg0.type()); symbol_expr.set_identifier(arg0.get_string(ID_class)+"."+arg0.get_string(ID_component_name)); results[0]=symbol_expr; } else if(statement=="putfield") { assert(op.size()==2 && results.size()==0); c = code_assignt(to_member(op[0], arg0), op[1]); } else if(statement=="putstatic") { assert(op.size()==1 && results.empty()); symbol_exprt symbol_expr(arg0.type()); symbol_expr.set_identifier(arg0.get_string(ID_class)+"."+arg0.get_string(ID_component_name)); c=code_assignt(symbol_expr, op[0]); } else if(statement==patternt("?2?")) // i2c etc. { assert(op.size()==1 && results.size()==1); results[0]=typecast_exprt(op[0], java_type_from_char(statement[2])); } else if(statement=="new") { // use temporary since the stack symbol might get duplicated assert(op.empty() && results.size()==1); const pointer_typet ref_type(arg0.type()); exprt java_new_expr=side_effect_exprt(ID_java_new, ref_type); if(!i_it->source_location.get_line().empty()) java_new_expr.add_source_location()=i_it->source_location; const exprt tmp=tmp_variable("new", ref_type); c=code_assignt(tmp, java_new_expr); results[0]=tmp; } else if(statement=="newarray" || statement=="anewarray") { // the op is the array size assert(op.size()==1 && results.size()==1); char element_type; if(statement=="newarray") { irep_idt id=arg0.type().id(); if(id==ID_bool) element_type='z'; else if(id==ID_char) element_type='c'; else if(id==ID_float) element_type='f'; else if(id==ID_double) element_type='d'; else if(id==ID_byte) element_type='b'; else if(id==ID_short) element_type='s'; else if(id==ID_int) element_type='i'; else if(id==ID_long) element_type='j'; else element_type='?'; } else element_type='a'; const pointer_typet ref_type=java_array_type(element_type); side_effect_exprt java_new_array(ID_java_new_array, ref_type); java_new_array.copy_to_operands(op[0]); if(!i_it->source_location.get_line().empty()) java_new_array.add_source_location()=i_it->source_location; const exprt tmp=tmp_variable("newarray", ref_type); c=code_assignt(tmp, java_new_array); results[0]=tmp; } else if(statement=="multianewarray") { // The first argument is the type, the second argument is the dimension. // The size of each dimension is on the stack. irep_idt number=to_constant_expr(arg1).get_value(); unsigned dimension=safe_c_str2unsigned(number.c_str()); op=pop(dimension); assert(results.size()==1); // arg0.type() const pointer_typet ref_type=java_array_type('a'); side_effect_exprt java_new_array(ID_java_new_array, ref_type); java_new_array.operands()=op; if(!i_it->source_location.get_line().empty()) java_new_array.add_source_location()=i_it->source_location; const exprt tmp=tmp_variable("newarray", ref_type); c=code_assignt(tmp, java_new_array); results[0]=tmp; } else if(statement=="arraylength") { assert(op.size()==1 && results.size()==1); exprt pointer= typecast_exprt(op[0], java_array_type(statement[0])); const dereference_exprt array(pointer, pointer.type().subtype()); assert(pointer.type().subtype().id()==ID_symbol); const member_exprt length(array, "length", java_int_type()); results[0]=length; } else if(statement=="tableswitch" || statement=="lookupswitch") { assert(op.size()==1 && results.size()==0); // we turn into switch-case code_switcht code_switch; code_switch.add_source_location()=i_it->source_location; code_switch.value()=op[0]; code_blockt code_block; code_block.add_source_location()=i_it->source_location; bool is_label=true; for(instructiont::argst::const_iterator a_it=i_it->args.begin(); a_it!=i_it->args.end(); a_it++, is_label=!is_label) { if(is_label) { code_switch_caset code_case; code_case.add_source_location()=i_it->source_location; irep_idt number=to_constant_expr(*a_it).get_value(); code_case.code()=code_gotot(label(number)); code_case.code().add_source_location()=i_it->source_location; if(a_it==i_it->args.begin()) code_case.set_default(); else { instructiont::argst::const_iterator prev=a_it; prev--; code_case.case_op()=typecast_exprt(*prev, op[0].type()); code_case.case_op().add_source_location()=i_it->source_location; } code_block.add(code_case); } } code_switch.body()=code_block; c=code_switch; } else if(statement=="pop" || statement=="pop2") { // these are skips c=code_skipt(); // pop2 removes two single-word items from the stack (e.g. two // integers, or an integer and an object reference) or one // two-word item (i.e. a double or a long). // http://cs.au.dk/~mis/dOvs/jvmspec/ref-pop2.html if(statement=="pop2" && op[0].type().get_unsigned_int(ID_width)==32) pop(1); } else if(statement=="instanceof") { assert(op.size()==1 && results.size()==1); results[0]= binary_predicate_exprt(op[0], "java_instanceof", arg0); } else { c=codet(statement); c.operands()=op; } if(!i_it->source_location.get_line().empty()) c.add_source_location()=i_it->source_location; push(results); a_it->second.done=true; for(std::list<unsigned>::iterator it=a_it->second.successors.begin(); it!=a_it->second.successors.end(); ++it) { address_mapt::iterator a_it2=address_map.find(*it); assert(a_it2!=address_map.end()); if(!stack.empty() && a_it2->second.predecessors.size()>1) { // copy into temporaries code_blockt more_code; // introduce temporaries when successor is seen for the first // time if(a_it2->second.stack.empty()) { for(stackt::iterator s_it=stack.begin(); s_it!=stack.end(); ++s_it) { symbol_exprt lhs=tmp_variable("$stack", s_it->type()); code_assignt a(lhs, *s_it); more_code.copy_to_operands(a); s_it->swap(lhs); } } else { assert(a_it2->second.stack.size()==stack.size()); stackt::const_iterator os_it=a_it2->second.stack.begin(); for(stackt::iterator s_it=stack.begin(); s_it!=stack.end(); ++s_it) { assert(has_prefix(os_it->get_string(ID_C_base_name), "$stack")); symbol_exprt lhs=to_symbol_expr(*os_it); code_assignt a(lhs, *s_it); more_code.copy_to_operands(a); s_it->swap(lhs); ++os_it; } } if(results.empty()) { more_code.copy_to_operands(c); c.swap(more_code); } else { c.make_block(); forall_operands(o_it, more_code) c.copy_to_operands(*o_it); } } a_it2->second.stack=stack; } } // TODO: add exception handlers from exception table // review successor computation of athrow! code_blockt code; // temporaries for(const auto & var : tmp_vars) { code.add(code_declt(var)); } for(const auto & it : address_map) { const unsigned address=it.first; assert(it.first==it.second.source->address); const codet &c=it.second.code; if(targets.find(address)!=targets.end()) code.add(code_labelt(label(i2string(address)), c)); else if(c.get_statement()!=ID_skip) code.add(c); } return code; }
void goto_checkt::pointer_validity_check( const dereference_exprt &expr, const guardt &guard) { if(!enable_pointer_check) return; const exprt &pointer=expr.op0(); const typet &pointer_type=to_pointer_type(ns.follow(pointer.type())); assert(base_type_eq(pointer_type.subtype(), expr.type(), ns)); local_bitvector_analysist::flagst flags= local_bitvector_analysis->get(t, pointer); const typet &dereference_type=pointer_type.subtype(); // For Java, we only need to check for null if(mode==ID_java) { if(flags.is_unknown() || flags.is_null()) { notequal_exprt not_eq_null(pointer, gen_zero(pointer.type())); add_guarded_claim( not_eq_null, "reference is null", "pointer dereference", expr.find_source_location(), expr, guard); } } else { if(flags.is_unknown() || flags.is_null()) { add_guarded_claim( not_exprt(null_pointer(pointer)), "dereference failure: pointer NULL", "pointer dereference", expr.find_source_location(), expr, guard); } if(flags.is_unknown()) add_guarded_claim( not_exprt(invalid_pointer(pointer)), "dereference failure: pointer invalid", "pointer dereference", expr.find_source_location(), expr, guard); if(flags.is_uninitialized()) add_guarded_claim( not_exprt(invalid_pointer(pointer)), "dereference failure: pointer uninitialized", "pointer dereference", expr.find_source_location(), expr, guard); if(mode != ID_java) { if(flags.is_unknown() || flags.is_dynamic_heap()) add_guarded_claim( not_exprt(deallocated(pointer, ns)), "dereference failure: deallocated dynamic object", "pointer dereference", expr.find_source_location(), expr, guard); if(flags.is_unknown() || flags.is_dynamic_local()) add_guarded_claim( not_exprt(dead_object(pointer, ns)), "dereference failure: dead object", "pointer dereference", expr.find_source_location(), expr, guard); } if(enable_bounds_check) { if(flags.is_unknown() || flags.is_dynamic_heap()) { exprt dynamic_bounds= or_exprt(dynamic_object_lower_bound(pointer), dynamic_object_upper_bound(pointer, dereference_type, ns)); add_guarded_claim( implies_exprt(malloc_object(pointer, ns), not_exprt(dynamic_bounds)), "dereference failure: dynamic object bounds", "pointer dereference", expr.find_source_location(), expr, guard); } } if(enable_bounds_check) { if(flags.is_unknown() || flags.is_dynamic_local() || flags.is_static_lifetime()) { exprt object_bounds= or_exprt(object_lower_bound(pointer), object_upper_bound(pointer, dereference_type, ns)); add_guarded_claim( or_exprt(dynamic_object(pointer), not_exprt(object_bounds)), "dereference failure: object bounds", "pointer dereference", expr.find_source_location(), expr, guard); } } } }
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); }
bool strategy_solver_binsearcht::iterate(invariantt &_inv) { tpolyhedra_domaint::templ_valuet &inv= static_cast<tpolyhedra_domaint::templ_valuet &>(_inv); bool improved=false; solver.new_context(); // for improvement check exprt inv_expr=tpolyhedra_domain.to_pre_constraints(inv); #if 0 debug() << "improvement check: " << eom; debug() << "pre-inv: " << from_expr(ns, "", inv_expr) << eom; #endif solver << inv_expr; exprt::operandst strategy_cond_exprs; tpolyhedra_domain.make_not_post_constraints( inv, strategy_cond_exprs, strategy_value_exprs); strategy_cond_literals.resize(strategy_cond_exprs.size()); #if 0 debug() << "post-inv: "; #endif for(std::size_t i=0; i<strategy_cond_exprs.size(); i++) { #if 0 debug() << (i>0 ? " || " : "") << from_expr(ns, "", strategy_cond_exprs[i]); #endif strategy_cond_literals[i]=solver.convert(strategy_cond_exprs[i]); // solver.set_frozen(strategy_cond_literals[i]); strategy_cond_exprs[i]=literal_exprt(strategy_cond_literals[i]); } #if 0 debug() << eom; #endif solver << or_exprt(disjunction(strategy_cond_exprs), literal_exprt(assertion_check)); #if 0 debug() << "solve(): "; #endif if(solver()==decision_proceduret::D_SATISFIABLE) // improvement check { #if 0 debug() << "SAT" << eom; #endif #if 0 for(std::size_t i=0; i<solver.formula.size(); i++) { debug() << "literal: " << solver.formula[i] << " " << solver.l_get(solver.formula[i]) << eom; } for(std::size_t i=0; i<tpolyhedra_domain.template_size(); i++) { exprt c=tpolyhedra_domain.get_row_post_constraint(i, inv[i]); debug() << "cond: " << from_expr(ns, "", c) << " " << from_expr(ns, "", solver.get(c)) << eom; debug() << "expr: " << from_expr(ns, "", strategy_value_exprs[i]) << " " << from_expr( ns, "", simplify_const(solver.get(strategy_value_exprs[i]))) << eom; debug() << "guards: " << from_expr(ns, "", tpolyhedra_domain.templ[i].pre_guard) << " " << from_expr( ns, "", solver.get(tpolyhedra_domain.templ[i].pre_guard)) << eom; debug() << "guards: " << from_expr(ns, "", tpolyhedra_domain.templ[i].post_guard) << " " << from_expr( ns, "", solver.get(tpolyhedra_domain.templ[i].post_guard)) << eom; } #endif std::size_t row=0; for(; row<strategy_cond_literals.size(); row++) { if(solver.l_get(strategy_cond_literals[row]).is_true()) break; // we've found a row to improve } if(row==strategy_cond_literals.size()) { // No, we haven't found one. // This can only happen if the assertions failed. solver.pop_context(); return FAILED; } debug() << "improving row: " << row << eom; std::set<tpolyhedra_domaint::rowt> improve_rows; improve_rows.insert(row); tpolyhedra_domaint::row_valuet upper= tpolyhedra_domain.get_max_row_value(row); tpolyhedra_domaint::row_valuet lower= simplify_const(solver.get(strategy_value_exprs[row])); solver.pop_context(); // improvement check solver.new_context(); // symbolic value system exprt pre_inv_expr= tpolyhedra_domain.to_symb_pre_constraints(inv, improve_rows); solver << pre_inv_expr; exprt post_inv_expr=tpolyhedra_domain.get_row_symb_post_constraint(row); solver << post_inv_expr; #if 0 debug() << "symbolic value system: " << eom; debug() << "pre-inv: " << from_expr(ns, "", pre_inv_expr) << eom; debug() << "post-inv: " << from_expr(ns, "", post_inv_expr) << eom; #endif while(tpolyhedra_domain.less_than(lower, upper)) { tpolyhedra_domaint::row_valuet middle= tpolyhedra_domain.between(lower, upper); if(!tpolyhedra_domain.less_than(lower, middle)) middle=upper; // row_symb_value >= middle exprt c= tpolyhedra_domain.get_row_symb_value_constraint(row, middle, true); #if 0 debug() << "upper: " << from_expr(ns, "", upper) << eom; debug() << "middle: " << from_expr(ns, "", middle) << eom; debug() << "lower: " << from_expr(ns, "", lower) << eom; #endif solver.new_context(); // binary search iteration #if 0 debug() << "constraint: " << from_expr(ns, "", c) << eom; #endif solver << c; if(solver()==decision_proceduret::D_SATISFIABLE) { #if 0 debug() << "SAT" << eom; #endif #if 0 for(std::size_t i=0; i<tpolyhedra_domain.template_size(); i++) { debug() << from_expr(ns, "", tpolyhedra_domain.get_row_symb_value(i)) << " " << from_expr( ns, "", solver.get(tpolyhedra_domain.get_row_symb_value(i))) << eom; } #endif #if 0 for(const auto &rm : renaming_map) { debug() << "replace_map (1st): " << from_expr(ns, "", rm.first) << " " << from_expr(ns, "", solver.get(rm.first)) << eom; debug() << "replace_map (2nd): " << from_expr(ns, "", rm.second) << " " << from_expr(ns, "", solver.get(rm.second)) << eom; } #endif lower=simplify_const( solver.get(tpolyhedra_domain.get_row_symb_value(row))); } else { #if 0 debug() << "UNSAT" << eom; #endif #if 0 for(std::size_t i=0; i<solver.formula.size(); ++i) { if(solver.solver->is_in_conflict(solver.formula[i])) debug() << "is_in_conflict: " << solver.formula[i] << eom; else debug() << "not_in_conflict: " << solver.formula[i] << eom; } #endif if(!tpolyhedra_domain.less_than(middle, upper)) middle=lower; upper=middle; } solver.pop_context(); // binary search iteration } debug() << "update value: " << from_expr(ns, "", lower) << eom; solver.pop_context(); // symbolic value system tpolyhedra_domain.set_row_value(row, lower, inv); improved=true; } else { #if 0 debug() << "UNSAT" << eom; #endif #ifdef DEBUG_FORMULA for(std::size_t i=0; i<solver.formula.size(); ++i) { if(solver.solver->is_in_conflict(solver.formula[i])) debug() << "is_in_conflict: " << solver.formula[i] << eom; else debug() << "not_in_conflict: " << solver.formula[i] << eom; } #endif solver.pop_context(); // improvement check } return improved; }
guardt &operator |= (guardt &g1, const guardt &g2) { if(g2.is_false() || g1.is_true()) return g1; if(g1.is_false() || g2.is_true()) { g1=g2; return g1; } if(g1.id()!=ID_and || g2.id()!=ID_and) { exprt tmp(g2); tmp.make_not(); if(tmp==g1) g1.make_true(); else g1=or_exprt(g1, g2); // TODO: make simplify more capable and apply here return g1; } // find common prefix sort_and_join(g1); guardt g2_sorted=g2; sort_and_join(g2_sorted); exprt::operandst &op1=g1.operands(); const exprt::operandst &op2=g2_sorted.operands(); exprt::operandst n_op1, n_op2; n_op1.reserve(op1.size()); n_op2.reserve(op2.size()); exprt::operandst::iterator it1=op1.begin(); for(exprt::operandst::const_iterator it2=op2.begin(); it2!=op2.end(); ++it2) { while(it1!=op1.end() && *it1<*it2) { n_op1.push_back(*it1); it1=op1.erase(it1); } if(it1!=op1.end() && *it1==*it2) ++it1; else n_op2.push_back(*it2); } while(it1!=op1.end()) { n_op1.push_back(*it1); it1=op1.erase(it1); } if(n_op2.empty()) return g1; // end of common prefix exprt and_expr1=conjunction(n_op1); exprt and_expr2=conjunction(n_op2); g1=conjunction(op1); exprt tmp(and_expr2); tmp.make_not(); if(tmp!=and_expr1) { if(and_expr1.is_true() || and_expr2.is_true()) { } else // TODO: make simplify more capable and apply here g1.add(or_exprt(and_expr1, and_expr2)); } return g1; }
bool solver_enumerationt::iterate(invariantt &_inv) { tpolyhedra_domaint::templ_valuet &inv = static_cast<tpolyhedra_domaint::templ_valuet &>(_inv); bool improved = false; literalt activation_literal = new_context(); exprt inv_expr = tpolyhedra_domain.to_pre_constraints(inv); debug() << "pre-inv: " << from_expr(ns,"",inv_expr) << eom; #ifndef DEBUG_FORMULA solver << or_exprt(inv_expr, literal_exprt(activation_literal)); #else debug() << "literal " << activation_literal << eom; literalt l = solver.convert(or_exprt(inv_expr, literal_exprt(activation_literal))); if(!l.is_constant()) { debug() << "literal " << l << ": " << from_expr(ns,"",or_exprt(inv_expr, literal_exprt(activation_literal))) <<eom; formula.push_back(l); } #endif exprt::operandst strategy_cond_exprs; tpolyhedra_domain.make_not_post_constraints(inv, strategy_cond_exprs, strategy_value_exprs); #ifndef DEBUG_FORMULA solver << or_exprt(disjunction(strategy_cond_exprs), literal_exprt(activation_literal)); #else exprt expr_act= or_exprt(disjunction(strategy_cond_exprs), literal_exprt(activation_literal)); l = solver.convert(expr_act); if(!l.is_constant()) { debug() << "literal " << l << ": " << from_expr(ns,"", expr_act) <<eom; formula.push_back(l); } #endif debug() << "solve(): "; #ifdef DEBUG_FORMULA bvt whole_formula = formula; whole_formula.insert(whole_formula.end(),activation_literals.begin(),activation_literals.end()); solver.set_assumptions(whole_formula); #endif if(solve() == decision_proceduret::D_SATISFIABLE) { debug() << "SAT" << eom; #if 0 for(unsigned i=0; i<whole_formula.size(); i++) { debug() << "literal: " << whole_formula[i] << " " << solver.l_get(whole_formula[i]) << eom; } for(unsigned i=0; i<tpolyhedra_domain.template_size(); i++) { exprt c = tpolyhedra_domain.get_row_constraint(i,inv[i]); debug() << "cond: " << from_expr(ns, "", c) << " " << from_expr(ns, "", solver.get(c)) << eom; debug() << "guards: " << from_expr(ns, "", tpolyhedra_domain.templ.pre_guards[i]) << " " << from_expr(ns, "", solver.get(tpolyhedra_domain.templ.pre_guards[i])) << eom; debug() << "guards: " << from_expr(ns, "", tpolyhedra_domain.templ.post_guards[i]) << " " << from_expr(ns, "", solver.get(tpolyhedra_domain.templ.post_guards[i])) << eom; } for(replace_mapt::const_iterator it=renaming_map.begin(); it!=renaming_map.end(); ++it) { debug() << "replace_map (1st): " << from_expr(ns, "", it->first) << " " << from_expr(ns, "", solver.get(it->first)) << eom; debug() << "replace_map (2nd): " << from_expr(ns, "", it->second) << " " << from_expr(ns, "", solver.get(it->second)) << eom; } #endif tpolyhedra_domaint::templ_valuet new_value; tpolyhedra_domain.initialize(new_value); for(unsigned row=0;row<tpolyhedra_domain.template_size(); row++) { tpolyhedra_domaint::row_valuet v = simplify_const(solver.get(strategy_value_exprs[row])); tpolyhedra_domain.set_row_value(row,v,new_value); debug() << "value: " << from_expr(ns,"",v) << eom; } tpolyhedra_domain.join(inv,new_value); improved = true; } else { debug() << "UNSAT" << eom; #ifdef DEBUG_FORMULA for(unsigned i=0; i<whole_formula.size(); i++) { if(solver.is_in_conflict(whole_formula[i])) debug() << "is_in_conflict: " << whole_formula[i] << eom; else debug() << "not_in_conflict: " << whole_formula[i] << eom; } #endif } pop_context(); return improved; }
exprt summarizer_bw_termt::compute_precondition( local_SSAt &SSA, summaryt &summary, const exprt::operandst &postconditions, incremental_solvert &solver, template_generator_summaryt &template_generator, bool context_sensitive) { exprt postcond=not_exprt(conjunction(postconditions)); // compute backward summary exprt bw_transformer, bw_invariant, bw_precondition; if(!template_generator.out_vars().empty()) { ssa_analyzert analyzer; analyzer.set_message_handler(get_message_handler()); analyzer(solver, SSA, postcond, template_generator); analyzer.get_result(bw_transformer, template_generator.inout_vars()); analyzer.get_result(bw_invariant, template_generator.loop_vars()); analyzer.get_result(bw_precondition, template_generator.out_vars()); // statistics solver_instances+=analyzer.get_number_of_solver_instances(); solver_calls+=analyzer.get_number_of_solver_calls(); } #if 1 // TODO: yet another workaround for ssa_analyzer // not being able to handle empty templates properly else { solver << SSA; solver.new_context(); solver << SSA.get_enabling_exprs(); solver << postcond; exprt result=true_exprt(); if(solver()==decision_proceduret::D_UNSATISFIABLE) result=false_exprt(); solver.pop_context(); bw_transformer=result; bw_invariant=result; bw_precondition=result; } #endif bw_transformer=not_exprt(bw_transformer); bw_invariant=not_exprt(bw_invariant); bw_precondition=not_exprt(bw_precondition); if(context_sensitive && !summary.bw_postcondition.is_true()) { bw_transformer=implies_exprt(summary.bw_postcondition, bw_transformer); bw_invariant=implies_exprt(summary.bw_postcondition, bw_invariant); bw_precondition=implies_exprt(summary.bw_postcondition, bw_precondition); } // join // TODO: should go into summaryt if(summary.bw_transformer.is_nil()) { summary.bw_transformer=bw_transformer; summary.bw_invariant=bw_invariant; summary.bw_precondition=bw_precondition; } else { summary.bw_transformer=or_exprt(summary.bw_transformer, bw_transformer); summary.bw_invariant=or_exprt(summary.bw_invariant, bw_invariant); summary.bw_precondition=or_exprt(summary.bw_precondition, bw_precondition); } return bw_precondition; }