bool string_abstractiont::build_wrap(const exprt &object, exprt &dest, bool write) { // debugging if(build(object, dest, write)) return true; // extra consistency check // use // #define build_wrap(a,b,c) build(a,b,c) // to avoid it const typet &a_t=build_abstraction_type(object.type()); /*assert(type_eq(dest.type(), a_t, ns) || (dest.type().id()==ID_array && a_t.id()==ID_pointer && type_eq(dest.type().subtype(), a_t.subtype(), ns))); */ if(!type_eq(dest.type(), a_t, ns) && !(dest.type().id()==ID_array && a_t.id()==ID_pointer && type_eq(dest.type().subtype(), a_t.subtype(), ns))) { std::string msg="warning: inconsistent abstract type for "+object.pretty(); warning(msg); return true; } return false; }
void symex_dereference_statet::get_value_set( const exprt &expr, value_setst::valuest &value_set) { renaming_nst renaming_ns(goto_symex.ns, state); state.value_set.get_value_set(expr, value_set, renaming_ns); #if 0 std::cout << "**************************\n"; state.value_set.output(std::cout, renaming_ns); std::cout << "**************************\n"; #endif #if 0 std::cout << "E: " << expr.pretty() << std::endl; #endif #if 0 std::cout << "**************************\n"; for(expr_sett::const_iterator it=value_set.begin(); it!=value_set.end(); it++) std::cout << from_expr(renaming_ns, "", *it) << std::endl; std::cout << "**************************\n"; #endif }
bool languaget::from_expr( const exprt &expr, std::string &code, const namespacet &ns) { code=expr.pretty(); return false; }
exprt dereferencet::dereference_rec( const exprt &address, const exprt &offset, const typet &type) { if(address.id()==ID_address_of) { const address_of_exprt &address_of_expr=to_address_of_expr(address); const exprt &object=address_of_expr.object(); return read_object(object, offset, type); } else if(address.id()==ID_typecast) { const typecast_exprt &typecast_expr=to_typecast_expr(address); return dereference_typecast(typecast_expr, offset, type); } else if(address.id()==ID_plus) { // pointer arithmetic if(address.operands().size()<2) throw "plus with less than two operands"; return dereference_plus(address, offset, type); } else if(address.id()==ID_if) { const if_exprt &if_expr=to_if_expr(address); return dereference_if(if_expr, offset, type); } else if(address.id()==ID_constant) { const typet result_type=ns.follow(address.type()).subtype(); // pointer-typed constant if(to_constant_expr(address).get_value()==ID_NULL) // NULL { // we turn this into (type *)0 exprt zero=gen_zero(index_type()); return dereference_rec( typecast_exprt(zero, address.type()), offset, type); } else throw "dereferencet: unexpected pointer constant "+address.pretty(); } else { throw "failed to dereference `"+address.id_string()+"'"; } }
void jsil_typecheckt::make_type_compatible( exprt &expr, const typet &type, bool must) { if(type.id().empty() || type.is_nil()) { err_location(expr); error() << "make_type_compatible got empty type: " << expr.pretty() << eom; throw 0; } if(expr.type().id().empty() || expr.type().is_nil()) { // Type is not yet set update_expr_type(expr, type); return; } if(must) { if(jsil_incompatible_types(expr.type(), type)) { err_location(expr); error() << "failed to typecheck expr " << expr.pretty() << " with type " << expr.type().pretty() << "; required type " << type.pretty() << eom; throw 0; } } else if(!jsil_is_subtype(type, expr.type())) { // Types are not compatible typet upper=jsil_union(expr.type(), type); update_expr_type(expr, upper); } }
void subsitute_invariants_rec( const invariant_sett::invariantst &invariants, exprt &dest) { if((dest.id()==ID_and || dest.id()==ID_or || dest.id()==ID_not) && dest.type().id()==ID_bool) { Forall_operands(it, dest) subsitute_invariants_rec(invariants, *it); } else { #if 0 for(invariant_sett::invariantst::expr_sett::const_iterator it=invariants.expr_set().begin(); it!=invariants.expr_set().end(); it++) std::cout << "I: " << it->pretty() << std::endl; std::cout << "DEST: " << dest.pretty() << std::endl; #endif if(invariants.expr_set().find(dest)!= invariants.expr_set().end()) { dest.make_true(); } else { // inverted? exprt tmp(dest); tmp.make_not(); if(invariants.expr_set().find(tmp)!= invariants.expr_set().end()) { dest.make_false(); } } } }
void goto_convertt::rewrite_boolean(exprt &expr) { assert(expr.id()==ID_and || expr.id()==ID_or); if(!expr.is_boolean()) throw "`"+expr.id_string()+"' " "must be Boolean, but got "+expr.pretty(); // re-write "a && b" into nested a?b:0 // re-write "a || b" into nested a?1:b exprt tmp; if(expr.id()==ID_and) tmp=true_exprt(); else // ID_or tmp=false_exprt(); exprt::operandst &ops=expr.operands(); // start with last one for(int i=int(ops.size())-1; i>=0; i--) { exprt &op=ops[i]; if(!op.is_boolean()) throw "`"+expr.id_string()+"' takes Boolean " "operands only, but got "+op.pretty(); if(expr.id()==ID_and) { if_exprt if_e(op, tmp, false_exprt()); tmp.swap(if_e); } else // ID_or { if_exprt if_e(op, true_exprt(), tmp); tmp.swap(if_e); } } expr.swap(tmp); }
literalt cvc_convt::convert(const exprt &expr) { //out << "%% E: " << expr << std::endl; if(expr.type().id()!=ID_bool) { std::string msg="cvc_convt::convert got " "non-boolean expression: "; msg+=expr.pretty(); throw msg; } // Three special cases in which we don't need to generate // a handle. if(expr.is_true()) return const_literal(true); else if(expr.is_false()) return const_literal(false); else if(expr.id()==ID_literal) return to_literal_expr(expr).get_literal(); // Generate new handle literalt l(no_boolean_variables, false); no_boolean_variables++; find_symbols(expr); // define new handle out << "ASSERT "; convert_literal(l); out << " <=> ("; convert_expr(expr); out << ");" << std::endl << std::endl; return l; }
void jsil_typecheckt::typecheck_expr_main(exprt &expr) { if(expr.id()==ID_code) { err_location(expr); error() << "typecheck_expr_main got code: " << expr.pretty() << eom; throw 0; } else if(expr.id()==ID_symbol) typecheck_symbol_expr(to_symbol_expr (expr)); else if(expr.id()==ID_constant) { } else { // expressions are expected not to have type set just yet assert(expr.type().is_nil()||expr.type().id().empty()); if (expr.id()==ID_null || expr.id()=="undefined" || expr.id()==ID_empty) typecheck_expr_constant(expr); else if(expr.id()=="null_type" || expr.id()=="undefined_type" || expr.id()==ID_boolean || expr.id()==ID_string || expr.id()=="number" || expr.id()=="builtin_object" || expr.id()=="user_object" || expr.id()=="object" || expr.id()==ID_reference || expr.id()==ID_member || expr.id()=="variable") expr.type()=jsil_kind(); else if(expr.id()=="proto" || expr.id()=="fid" || expr.id()=="scope" || expr.id()=="constructid" || expr.id()=="primvalue" || expr.id()=="targetfunction" || expr.id()==ID_class) { // TODO: have a special type for builtin fields expr.type()=string_typet(); } else if(expr.id()==ID_not) typecheck_expr_unary_boolean(expr); else if(expr.id()=="string_to_num") typecheck_expr_unary_string(expr); else if(expr.id()==ID_unary_minus || expr.id()=="num_to_int32" || expr.id()=="num_to_uint32" || expr.id()==ID_bitnot) { typecheck_expr_unary_num(expr); expr.type()=floatbv_typet(); } else if(expr.id()=="num_to_string") { typecheck_expr_unary_num(expr); expr.type()=string_typet(); } else if(expr.id()==ID_equal) typecheck_exp_binary_equal(expr); else if(expr.id()==ID_lt || expr.id()==ID_le) typecheck_expr_binary_compare(expr); else if(expr.id()==ID_plus || expr.id()==ID_minus || expr.id()==ID_mult || expr.id()==ID_div || expr.id()==ID_mod || expr.id()==ID_bitand || expr.id()==ID_bitor || expr.id()==ID_bitxor || expr.id()==ID_shl || expr.id()==ID_shr || expr.id()==ID_lshr) typecheck_expr_binary_arith(expr); else if(expr.id()==ID_and || expr.id()==ID_or) typecheck_expr_binary_boolean(expr); else if(expr.id()=="subtype_of") typecheck_expr_subtype(expr); else if(expr.id()==ID_concatenation) typecheck_expr_concatenation(expr); else if(expr.id()=="ref") typecheck_expr_ref(expr); else if(expr.id()=="field") typecheck_expr_field(expr); else if(expr.id()==ID_base) typecheck_expr_base(expr); else if(expr.id()==ID_typeof) expr.type()=jsil_kind(); else if(expr.id()=="new") expr.type()=jsil_user_object_type(); else if(expr.id()=="hasField") typecheck_expr_has_field(expr); else if(expr.id()==ID_index) typecheck_expr_index(expr); else if(expr.id()=="delete") typecheck_expr_delete(expr); else if(expr.id()=="protoField") typecheck_expr_proto_field(expr); else if(expr.id()=="protoObj") typecheck_expr_proto_obj(expr); else if(expr.id()==ID_side_effect) typecheck_expr_side_effect_throw(to_side_effect_expr_throw(expr)); else { err_location(expr); error() << "unexpected expression: " << expr.pretty() << eom; throw 0; } } }
void boolbvt::convert_add_sub(const exprt &expr, bvt &bv) { const typet &type=ns.follow(expr.type()); if(type.id()!=ID_unsignedbv && type.id()!=ID_signedbv && type.id()!=ID_fixedbv && type.id()!=ID_floatbv && type.id()!=ID_range && type.id()!=ID_vector) return conversion_failed(expr, bv); unsigned width=boolbv_width(type); if(width==0) return conversion_failed(expr, bv); const exprt::operandst &operands=expr.operands(); if(operands.size()==0) throw "operand "+expr.id_string()+" takes at least one operand"; const exprt &op0=expr.op0(); if(op0.type()!=type) { std::cerr << expr.pretty() << std::endl; throw "add/sub with mixed types"; } convert_bv(op0, bv); if(bv.size()!=width) throw "convert_add_sub: unexpected operand 0 width"; bool subtract=(expr.id()==ID_minus || expr.id()=="no-overflow-minus"); bool no_overflow=(expr.id()=="no-overflow-plus" || expr.id()=="no-overflow-minus"); typet arithmetic_type= (type.id()==ID_vector)?ns.follow(type.subtype()):type; bv_utilst::representationt rep= (arithmetic_type.id()==ID_signedbv || arithmetic_type.id()==ID_fixedbv)?bv_utilst::SIGNED: bv_utilst::UNSIGNED; for(exprt::operandst::const_iterator it=operands.begin()+1; it!=operands.end(); it++) { if(it->type()!=type) { std::cerr << expr.pretty() << std::endl; throw "add/sub with mixed types"; } bvt op; convert_bv(*it, op); if(op.size()!=width) throw "convert_add_sub: unexpected operand width"; if(type.id()==ID_vector) { const typet &subtype=ns.follow(type.subtype()); unsigned sub_width=boolbv_width(subtype); if(sub_width==0 || width%sub_width!=0) throw "convert_add_sub: unexpected vector operand width"; unsigned size=width/sub_width; bv.resize(width); for(unsigned i=0; i<size; i++) { bvt tmp_op; tmp_op.resize(sub_width); for(unsigned j=0; j<tmp_op.size(); j++) { assert(i*sub_width+j<op.size()); tmp_op[j]=op[i*sub_width+j]; } bvt tmp_result; tmp_result.resize(sub_width); for(unsigned j=0; j<tmp_result.size(); j++) { assert(i*sub_width+j<bv.size()); tmp_result[j]=bv[i*sub_width+j]; } if(type.subtype().id()==ID_floatbv) { #ifdef HAVE_FLOATBV float_utilst float_utils(prop); float_utils.spec=to_floatbv_type(subtype); tmp_result=float_utils.add_sub(tmp_result, tmp_op, subtract); #else return conversion_failed(expr, bv); #endif } else tmp_result=bv_utils.add_sub(tmp_result, tmp_op, subtract); assert(tmp_result.size()==sub_width); for(unsigned j=0; j<tmp_result.size(); j++) { assert(i*sub_width+j<bv.size()); bv[i*sub_width+j]=tmp_result[j]; } } } else if(type.id()==ID_floatbv) { #ifdef HAVE_FLOATBV float_utilst float_utils(prop); float_utils.spec=to_floatbv_type(arithmetic_type); bv=float_utils.add_sub(bv, op, subtract); #else return conversion_failed(expr, bv); #endif } else if(no_overflow) bv=bv_utils.add_sub_no_overflow(bv, op, subtract, rep); else bv=bv_utils.add_sub(bv, op, subtract); } }
void goto_program_dereferencet::dereference_rec( exprt &expr, guardt &guard, const value_set_dereferencet::modet mode) { if(!dereference.has_dereference(expr)) return; if(expr.id()==ID_and || expr.id()==ID_or) { if(!expr.is_boolean()) throw expr.id_string()+" must be Boolean, but got "+ expr.pretty(); guardt old_guard=guard; for(unsigned i=0; i<expr.operands().size(); i++) { exprt &op=expr.operands()[i]; if(!op.is_boolean()) throw expr.id_string()+" takes Boolean operands only, but got "+ op.pretty(); if(dereference.has_dereference(op)) dereference_rec(op, guard, value_set_dereferencet::modet::READ); if(expr.id()==ID_or) { exprt tmp(op); tmp.make_not(); guard.add(tmp); } else guard.add(op); } guard.swap(old_guard); return; } else if(expr.id()==ID_if) { if(expr.operands().size()!=3) throw "if takes three arguments"; if(!expr.op0().is_boolean()) { std::string msg= "first argument of if must be boolean, but got " +expr.op0().pretty(); throw msg; } dereference_rec(expr.op0(), guard, value_set_dereferencet::modet::READ); bool o1=dereference.has_dereference(expr.op1()); bool o2=dereference.has_dereference(expr.op2()); if(o1) { guardt old_guard=guard; guard.add(expr.op0()); dereference_rec(expr.op1(), guard, mode); guard.swap(old_guard); } if(o2) { guardt old_guard=guard; exprt tmp(expr.op0()); tmp.make_not(); guard.add(tmp); dereference_rec(expr.op2(), guard, mode); guard.swap(old_guard); } return; } if(expr.id()==ID_address_of || expr.id()=="reference_to") { // turn &*p to p // this has *no* side effect! assert(expr.operands().size()==1); if(expr.op0().id()==ID_dereference) { assert(expr.op0().operands().size()==1); exprt tmp; tmp.swap(expr.op0().op0()); if(tmp.type()!=expr.type()) tmp.make_typecast(expr.type()); expr.swap(tmp); } } Forall_operands(it, expr) dereference_rec(*it, guard, mode); if(expr.id()==ID_dereference) { if(expr.operands().size()!=1) throw "dereference expects one operand"; dereference_location=expr.find_source_location(); exprt tmp=dereference.dereference( expr.op0(), guard, mode); expr.swap(tmp); } else if(expr.id()==ID_index) { // this is old stuff and will go away if(expr.operands().size()!=2) throw "index expects two operands"; if(expr.op0().type().id()==ID_pointer) { dereference_location=expr.find_source_location(); exprt tmp1(ID_plus, expr.op0().type()); tmp1.operands().swap(expr.operands()); exprt tmp2=dereference.dereference(tmp1, guard, mode); tmp2.swap(expr); } } }
exprt path_symex_statet::instantiate_rec( const exprt &src, bool propagate) { #ifdef DEBUG std::cout << "instantiate_rec: " << from_expr(var_map.ns, "", src) << std::endl; #endif const typet &src_type=var_map.ns.follow(src.type()); if(src_type.id()==ID_struct) // src is a struct { const struct_typet &struct_type=to_struct_type(src_type); const struct_typet::componentst &components=struct_type.components(); struct_exprt result(src.type()); result.operands().resize(components.size()); // split it up into components for(unsigned i=0; i<components.size(); i++) { const typet &subtype=components[i].type(); const irep_idt &component_name=components[i].get_name(); exprt new_src; if(src.id()==ID_struct) // struct constructor? { assert(src.operands().size()==components.size()); new_src=src.operands()[i]; } else new_src=member_exprt(src, component_name, subtype); // recursive call result.operands()[i]=instantiate_rec(new_src, propagate); } return result; // done } else if(src_type.id()==ID_array) // src is an array { const array_typet &array_type=to_array_type(src_type); const typet &subtype=array_type.subtype(); if(array_type.size().is_constant()) { mp_integer size; if(to_integer(array_type.size(), size)) throw "failed to convert array size"; unsigned long long size_int=integer2unsigned(size); array_exprt result(array_type); result.operands().resize(size_int); // split it up into elements for(unsigned long long i=0; i<size_int; ++i) { exprt index=from_integer(i, array_type.size().type()); exprt new_src=index_exprt(src, index, subtype); // array constructor? if(src.id()==ID_array) new_src=simplify_expr(new_src, var_map.ns); // recursive call result.operands()[i]=instantiate_rec(new_src, propagate); } return result; // done } else { // TODO } } else if(src_type.id()==ID_vector) // src is a vector { const vector_typet &vector_type=to_vector_type(src_type); const typet &subtype=vector_type.subtype(); if(!vector_type.size().is_constant()) throw "vector with non-constant size"; mp_integer size; if(to_integer(vector_type.size(), size)) throw "failed to convert vector size"; unsigned long long int size_int=integer2unsigned(size); vector_exprt result(vector_type); exprt::operandst &operands=result.operands(); operands.resize(size_int); // split it up into elements for(unsigned long long i=0; i<size_int; ++i) { exprt index=from_integer(i, vector_type.size().type()); exprt new_src=index_exprt(src, index, subtype); // vector constructor? if(src.id()==ID_vector) new_src=simplify_expr(new_src, var_map.ns); // recursive call operands[i]=instantiate_rec(new_src, propagate); } return result; // done } // check whether this is a symbol(.member|[index])* { exprt tmp_symbol_member_index= read_symbol_member_index(src, propagate); if(tmp_symbol_member_index.is_not_nil()) return tmp_symbol_member_index; // yes! } if(src.id()==ID_address_of) { assert(src.operands().size()==1); exprt tmp=src; tmp.op0()=instantiate_rec_address(tmp.op0(), propagate); return tmp; } else if(src.id()==ID_sideeffect) { // could be done separately const irep_idt &statement=to_side_effect_expr(src).get_statement(); if(statement==ID_nondet) { irep_idt id="symex::nondet"+i2string(var_map.nondet_count); var_map.nondet_count++; return symbol_exprt(id, src.type()); } else throw "instantiate_rec: unexpected side effect "+id2string(statement); } else if(src.id()==ID_dereference) { // dereferencet has run already, so we should only be left with // integer addresses. Will transform into __CPROVER_memory[] // eventually. } else if(src.id()==ID_index) { // avoids indefinite recursion above return src; } else if(src.id()==ID_member) { const typet &compound_type= var_map.ns.follow(to_member_expr(src).struct_op().type()); if(compound_type.id()==ID_struct) { // avoids indefinite recursion above return src; } else if(compound_type.id()==ID_union) { member_exprt tmp=to_member_expr(src); tmp.struct_op()=instantiate_rec(tmp.struct_op(), propagate); return tmp; } else { throw "member expects struct or union type"+src.pretty(); } } if(!src.has_operands()) return src; exprt src2=src; // recursive calls on structure of 'src' Forall_operands(it, src2) { exprt tmp_op=instantiate_rec(*it, propagate); *it=tmp_op; }
void goto_checkt::check_rec( const exprt &expr, guardt &guard, bool address) { // we don't look into quantifiers if(expr.id()==ID_exists || expr.id()==ID_forall) return; if(address) { if(expr.id()==ID_dereference) { assert(expr.operands().size()==1); check_rec(expr.op0(), guard, false); } else if(expr.id()==ID_index) { assert(expr.operands().size()==2); check_rec(expr.op0(), guard, true); check_rec(expr.op1(), guard, false); } else { forall_operands(it, expr) check_rec(*it, guard, true); } return; } if(expr.id()==ID_address_of) { assert(expr.operands().size()==1); check_rec(expr.op0(), guard, true); return; } else if(expr.id()==ID_and || expr.id()==ID_or) { if(!expr.is_boolean()) throw "`"+expr.id_string()+"' must be Boolean, but got "+ expr.pretty(); guardt old_guard=guard; for(unsigned i=0; i<expr.operands().size(); i++) { const exprt &op=expr.operands()[i]; if(!op.is_boolean()) throw "`"+expr.id_string()+"' takes Boolean operands only, but got "+ op.pretty(); check_rec(op, guard, false); if(expr.id()==ID_or) guard.add(not_exprt(op)); else guard.add(op); } guard.swap(old_guard); return; } else if(expr.id()==ID_if) { if(expr.operands().size()!=3) throw "if takes three arguments"; if(!expr.op0().is_boolean()) { std::string msg= "first argument of if must be boolean, but got " +expr.op0().pretty(); throw msg; } check_rec(expr.op0(), guard, false); { guardt old_guard=guard; guard.add(expr.op0()); check_rec(expr.op1(), guard, false); guard.swap(old_guard); } { guardt old_guard=guard; guard.add(not_exprt(expr.op0())); check_rec(expr.op2(), guard, false); guard.swap(old_guard); } return; } forall_operands(it, expr) check_rec(*it, guard, false); if(expr.id()==ID_index) { bounds_check(to_index_expr(expr), guard); } else if(expr.id()==ID_div) { div_by_zero_check(to_div_expr(expr), guard); if(expr.type().id()==ID_signedbv) integer_overflow_check(expr, guard); else if(expr.type().id()==ID_floatbv) { nan_check(expr, guard); float_overflow_check(expr, guard); } } else if(expr.id()==ID_shl || expr.id()==ID_ashr || expr.id()==ID_lshr) { undefined_shift_check(to_shift_expr(expr), guard); } else if(expr.id()==ID_mod) { mod_by_zero_check(to_mod_expr(expr), guard); } else if(expr.id()==ID_plus || expr.id()==ID_minus || expr.id()==ID_mult || expr.id()==ID_unary_minus) { if(expr.type().id()==ID_signedbv || expr.type().id()==ID_unsignedbv) { if(expr.operands().size()==2 && expr.op0().type().id()==ID_pointer) pointer_overflow_check(expr, guard); else integer_overflow_check(expr, guard); } else if(expr.type().id()==ID_floatbv) { nan_check(expr, guard); float_overflow_check(expr, guard); } else if(expr.type().id()==ID_pointer) { pointer_overflow_check(expr, guard); } } else if(expr.id()==ID_typecast) conversion_check(expr, guard); else if(expr.id()==ID_le || expr.id()==ID_lt || expr.id()==ID_ge || expr.id()==ID_gt) pointer_rel_check(expr, guard); else if(expr.id()==ID_dereference) pointer_validity_check(to_dereference_expr(expr), guard); }
void boolbvt::convert_floatbv_op(const exprt &expr, bvt &bv) { const exprt::operandst &operands=expr.operands(); if(operands.size()!=3) throw "operator "+expr.id_string()+" takes three operands"; const exprt &op0=expr.op0(); // first operand const exprt &op1=expr.op1(); // second operand const exprt &op2=expr.op2(); // rounding mode bvt bv0=convert_bv(op0); bvt bv1=convert_bv(op1); bvt bv2=convert_bv(op2); const typet &type=ns.follow(expr.type()); if(op0.type()!=type || op1.type()!=type) { std::cerr << expr.pretty() << std::endl; throw "float op with mixed types"; } float_utilst float_utils(prop); float_utils.set_rounding_mode(bv2); if(type.id()==ID_floatbv) { float_utils.spec=to_floatbv_type(expr.type()); if(expr.id()==ID_floatbv_plus) bv=float_utils.add_sub(bv0, bv1, false); else if(expr.id()==ID_floatbv_minus) bv=float_utils.add_sub(bv0, bv1, true); else if(expr.id()==ID_floatbv_mult) bv=float_utils.mul(bv0, bv1); else if(expr.id()==ID_floatbv_div) bv=float_utils.div(bv0, bv1); else if(expr.id()==ID_floatbv_rem) bv=float_utils.rem(bv0, bv1); else assert(false); } else if(type.id()==ID_vector || type.id()==ID_complex) { const typet &subtype=ns.follow(type.subtype()); if(subtype.id()==ID_floatbv) { float_utils.spec=to_floatbv_type(subtype); std::size_t width=boolbv_width(type); std::size_t sub_width=boolbv_width(subtype); if(sub_width==0 || width%sub_width!=0) throw "convert_floatbv_op: unexpected vector operand width"; std::size_t size=width/sub_width; bv.resize(width); for(std::size_t i=0; i<size; i++) { bvt tmp_bv0, tmp_bv1, tmp_bv; tmp_bv0.assign(bv0.begin()+i*sub_width, bv0.begin()+(i+1)*sub_width); tmp_bv1.assign(bv1.begin()+i*sub_width, bv1.begin()+(i+1)*sub_width); if(expr.id()==ID_floatbv_plus) tmp_bv=float_utils.add_sub(tmp_bv0, tmp_bv1, false); else if(expr.id()==ID_floatbv_minus) tmp_bv=float_utils.add_sub(tmp_bv0, tmp_bv1, true); else if(expr.id()==ID_floatbv_mult) tmp_bv=float_utils.mul(tmp_bv0, tmp_bv1); else if(expr.id()==ID_floatbv_div) tmp_bv=float_utils.div(tmp_bv0, tmp_bv1); else assert(false); assert(tmp_bv.size()==sub_width); assert(i*sub_width+sub_width-1<bv.size()); std::copy(tmp_bv.begin(), tmp_bv.end(), bv.begin()+i*sub_width); } } else return conversion_failed(expr, bv); } else return conversion_failed(expr, bv); }
void goto_checkt::check_rec(const exprt &expr, guardt &guard, bool address) { if (address) { if (expr.id() == "dereference") { assert(expr.operands().size() == 1); check_rec(expr.op0(), guard, false); } else if (expr.id() == "index") { assert(expr.operands().size() == 2); check_rec(expr.op0(), guard, true); check_rec(expr.op1(), guard, false); } else { forall_operands(it, expr) check_rec(*it, guard, true); } return; } if (expr.is_address_of()) { assert(expr.operands().size() == 1); check_rec(expr.op0(), guard, true); return; } else if (expr.is_and() || expr.id() == "or") { if (!expr.is_boolean()) throw expr.id_string() + " must be Boolean, but got " + expr.pretty(); unsigned old_guards = guard.size(); for (unsigned i = 0; i < expr.operands().size(); i++) { const exprt &op = expr.operands()[i]; if (!op.is_boolean()) throw expr.id_string() + " takes Boolean operands only, but got " + op.pretty(); check_rec(op, guard, false); if (expr.id() == "or") { exprt tmp(op); tmp.make_not(); expr2tc tmp_expr; migrate_expr(tmp, tmp_expr); guard.move(tmp_expr); } else { expr2tc tmp; migrate_expr(op, tmp); guard.add(tmp); } } guard.resize(old_guards); return; } else if (expr.id() == "if") { if (expr.operands().size() != 3) throw "if takes three arguments"; if (!expr.op0().is_boolean()) { std::string msg = "first argument of if must be boolean, but got " + expr.op0().to_string(); throw msg; } check_rec(expr.op0(), guard, false); { unsigned old_guard = guard.size(); expr2tc tmp; migrate_expr(expr.op0(), tmp); guard.add(tmp); check_rec(expr.op1(), guard, false); guard.resize(old_guard); } { unsigned old_guard = guard.size(); exprt tmp(expr.op0()); tmp.make_not(); expr2tc tmp_expr; migrate_expr(tmp, tmp_expr); guard.move(tmp_expr); check_rec(expr.op2(), guard, false); guard.resize(old_guard); } return; } forall_operands(it, expr) check_rec(*it, guard, false); if (expr.id() == "index") { bounds_check(expr, guard); } else if (expr.id() == "/") { div_by_zero_check(expr, guard); if (expr.type().id() == "signedbv") { overflow_check(expr, guard); } else if (expr.type().id() == "floatbv") { nan_check(expr, guard); } } else if (expr.id() == "+" || expr.id() == "-" || expr.id() == "*" || expr.id() == "unary-" || expr.id() == "typecast") { if (expr.type().id() == "signedbv") { overflow_check(expr, guard); } else if (expr.type().id() == "floatbv") { nan_check(expr, guard); } } else if (expr.id() == "<=" || expr.id() == "<" || expr.id() == ">=" || expr.id() == ">") { pointer_rel_check(expr, guard); } else if (expr.id() == "mod") { div_by_zero_check(expr, guard); if (expr.type().id() == "signedbv") { overflow_check(expr, guard); } else if (expr.type().id() == "floatbv") { nan_check(expr, guard); } } }
void goto_checkt::bounds_check(const exprt &expr, const guardt &guard) { if (options.get_bool_option("no-bounds-check")) return; if (expr.id() != "index") return; if (expr.operands().size() != 2) throw "index takes two operands"; // Don't bounds check the initial index of argv in the "main" function; it's // always correct, and just adds needless claims. In the past a "no bounds // check" attribute in old irep handled this. if (expr.op0().id_string() == "symbol" && expr.op0().identifier() == "c::argv'" && expr.op1().id_string() == "symbol" && expr.op1().identifier() == "c::argc'") return; if (expr.op0().id_string() == "symbol" && expr.op0().identifier() == "c::envp'" && expr.op1().id_string() == "symbol" && expr.op1().identifier() == "c::envp_size'") return; typet array_type = ns.follow(expr.op0().type()); if (array_type.id() == "pointer") return; // done by the pointer code else if (array_type.id() == "incomplete_array") { std::cerr << expr.pretty() << std::endl; throw "index got incomplete array"; } else if (!array_type.is_array()) throw "bounds check expected array type, got " + array_type.id_string(); // Otherwise, if there's a dereference in the array source, this bounds check // should be performed by the symex-time dereferencing code, as the base thing // being accessed may be anything. if (has_dereference(expr.op0())) return; std::string name = "array bounds violated: " + array_name(expr.op0()); const exprt &index = expr.op1(); if (index.type().id() != "unsignedbv") { // we undo typecasts to signedbv if (index.id() == "typecast" && index.operands().size() == 1 && index.op0().type().id() == "unsignedbv") { // ok } else { mp_integer i; if (!to_integer(index, i) && i >= 0) { // ok } else { exprt zero = gen_zero(index.type()); if (zero.is_nil()) throw "no zero constant of index type " + index.type().to_string(); exprt inequality(">=", bool_typet()); inequality.copy_to_operands(index, zero); add_guarded_claim(inequality, name + " lower bound", "array bounds", expr.find_location(), guard); } } } { if (array_type.size_irep().is_nil()) throw "index array operand of wrong type"; const exprt &size = (const exprt &) array_type.size_irep(); if (size.id() != "infinity") { exprt inequality("<", bool_typet()); inequality.copy_to_operands(index, size); // 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_location(), guard); } } }
exprt path_symex_statet::instantiate_rec( const exprt &src, bool propagate) { #ifdef DEBUG std::cout << "instantiate_rec: " << from_expr(var_map.ns, "", src) << '\n'; #endif // check whether this is a symbol(.member|[index])* if(is_symbol_member_index(src)) { exprt tmp_symbol_member_index= read_symbol_member_index(src, propagate); assert(tmp_symbol_member_index.is_not_nil()); return tmp_symbol_member_index; // yes! } if(src.id()==ID_address_of) { assert(src.operands().size()==1); exprt tmp=src; tmp.op0()=instantiate_rec_address(tmp.op0(), propagate); return tmp; } else if(src.id()==ID_side_effect) { // could be done separately const irep_idt &statement=to_side_effect_expr(src).get_statement(); if(statement==ID_nondet) { irep_idt id="symex::nondet"+std::to_string(var_map.nondet_count); var_map.nondet_count++; return symbol_exprt(id, src.type()); } else throw "instantiate_rec: unexpected side effect "+id2string(statement); } else if(src.id()==ID_dereference) { // dereferencet has run already, so we should only be left with // integer addresses. Will transform into __CPROVER_memory[] // eventually. } else if(src.id()==ID_member) { const typet &compound_type= var_map.ns.follow(to_member_expr(src).struct_op().type()); if(compound_type.id()==ID_struct) { // do nothing } else if(compound_type.id()==ID_union) { // should already have been rewritten to byte_extract throw "unexpected union member"; } else { throw "member expects struct or union type"+src.pretty(); } } else if(src.id()==ID_byte_extract_little_endian || src.id()==ID_byte_extract_big_endian) { } else if(src.id()==ID_symbol) { // must be SSA already, or code assert(src.type().id()==ID_code || src.get_bool(ID_C_SSA_symbol)); } if(!src.has_operands()) return src; exprt src2=src; // recursive calls on structure of 'src' Forall_operands(it, src2) { exprt tmp_op=instantiate_rec(*it, propagate); *it=tmp_op; }
void arrayst::collect_arrays(const exprt &a) { const array_typet &array_type= to_array_type(ns.follow(a.type())); if(a.id()==ID_with) { if(a.operands().size()!=3) throw "with expected to have three operands"; // check types if(!base_type_eq(array_type, a.op0().type(), ns)) { std::cout << a.pretty() << std::endl; throw "collect_arrays got with without matching types"; } arrays.make_union(a, a.op0()); collect_arrays(a.op0()); // make sure this shows as an application index_exprt index_expr; index_expr.type()=array_type.subtype(); index_expr.array()=a.op0(); index_expr.index()=a.op1(); record_array_index(index_expr); } else if(a.id()==ID_if) { if(a.operands().size()!=3) throw "if expected to have three operands"; // check types if(!base_type_eq(array_type, a.op1().type(), ns)) { std::cout << a.pretty() << std::endl; throw "collect_arrays got if without matching types"; } // check types if(!base_type_eq(array_type, a.op2().type(), ns)) { std::cout << a.pretty() << std::endl; throw "collect_arrays got if without matching types"; } arrays.make_union(a, a.op1()); arrays.make_union(a, a.op2()); collect_arrays(a.op1()); collect_arrays(a.op2()); } else if(a.id()==ID_symbol) { } else if(a.id()==ID_nondet_symbol) { } else if(a.id()==ID_member) { if(to_member_expr(a).struct_op().id()!=ID_symbol) throw "unexpected array expression: member with `"+a.op0().id_string()+"'"; } else if(a.id()==ID_constant || a.id()==ID_array || a.id()==ID_string_constant) { } else if(a.id()==ID_array_of) { } else throw "unexpected array expression: `"+a.id_string()+"'"; }