void goto_checkt::pointer_overflow_check( const exprt &expr, const guardt &guard) { if(!enable_pointer_overflow_check) return; if(expr.id()==ID_plus || expr.id()==ID_minus) { if(expr.operands().size()==2) { exprt overflow("overflow-"+expr.id_string(), bool_typet()); overflow.operands()=expr.operands(); add_guarded_claim( not_exprt(overflow), "pointer arithmetic overflow on "+expr.id_string(), "overflow", expr.find_source_location(), expr, guard); } } }
std::string format_constantt::operator()(const exprt &expr) { if(expr.is_constant()) { if(expr.type().id()==ID_natural || expr.type().id()==ID_integer || expr.type().id()==ID_unsignedbv || expr.type().id()==ID_signedbv) { mp_integer i; if(to_integer(expr, i)) return "(number conversion failed)"; return integer2string(i); } else if(expr.type().id()==ID_fixedbv) { return fixedbvt(expr).format(*this); } else if(expr.type().id()==ID_floatbv) { return ieee_floatt(expr).format(*this); } } else if(expr.id()==ID_string_constant) return expr.get_string(ID_value); return "(format-constant failed: "+expr.id_string()+")"; }
void arrayst::add_array_constraints( const index_sett &index_set, const exprt &expr) { if(expr.id()==ID_with) return add_array_constraints_with(index_set, to_with_expr(expr)); else if(expr.id()==ID_if) return add_array_constraints_if(index_set, to_if_expr(expr)); else if(expr.id()==ID_array_of) return add_array_constraints_array_of(index_set, to_array_of_expr(expr)); else if(expr.id()==ID_symbol || expr.id()==ID_nondet_symbol || expr.id()==ID_constant || expr.id()=="zero_string" || expr.id()==ID_array || expr.id()==ID_string_constant) { } else if(expr.id()==ID_member && to_member_expr(expr).struct_op().id()==ID_symbol) { } else throw "unexpected array expression: `"+expr.id_string()+"'"; }
void goto_checkt::pointer_rel_check( const exprt &expr, const guardt &guard) { if(!enable_pointer_check) return; if(expr.operands().size()!=2) throw expr.id_string()+" takes two arguments"; if(expr.op0().type().id()==ID_pointer && expr.op1().type().id()==ID_pointer) { // add same-object subgoal if(enable_pointer_check) { exprt same_object=::same_object(expr.op0(), expr.op1()); add_guarded_claim( same_object, "same object violation", "pointer", expr.find_source_location(), expr, guard); } } }
void cvc_convt::convert_expr(const exprt &expr) { const exprt::operandst &op=expr.operands(); if(expr.id()==ID_implies) { if(op.size()!=2) throw "implication takes two operands"; out << "("; convert_expr(op[0]); out << ") => ("; convert_expr(op[1]); out << ")"; } else if(expr.id()==ID_constraint_select_one) { if(op.size()<2) throw "constraint_select_one takes at least two operands"; // TODO throw "cvc_convt::convert_expr needs constraint_select_one"; } else if(expr.id()==ID_or || expr.id()==ID_and || expr.id()==ID_xor || expr.id()==ID_nor || expr.id()==ID_nand) { if(op.empty()) throw "operator `"+expr.id_string()+"' takes at least one operand"; else if(op.size()==1) convert_expr(op[0]); else { forall_expr(it, op) { if(it!=op.begin()) { if(expr.id()==ID_or) out << " OR "; else if(expr.id()==ID_nor) out << " NOR "; else if(expr.id()==ID_and) out << " AND "; else if(expr.id()==ID_nand) out << " NAND "; else if(expr.id()==ID_xor) out << " XOR "; else assert(false); } out << "("; convert_expr(*it); out << ")"; } } } else if(expr.id()==ID_not)
void goto_convertt::rewrite_boolean(exprt &expr) { assert(expr.id()==ID_and || expr.id()==ID_or); if(!expr.is_boolean()) throw "`"+expr.id_string()+"' " "must be Boolean, but got "+expr.pretty(); // re-write "a && b" into nested a?b:0 // re-write "a || b" into nested a?1:b exprt tmp; if(expr.id()==ID_and) tmp=true_exprt(); else // ID_or tmp=false_exprt(); exprt::operandst &ops=expr.operands(); // start with last one for(int i=int(ops.size())-1; i>=0; i--) { exprt &op=ops[i]; if(!op.is_boolean()) throw "`"+expr.id_string()+"' takes Boolean " "operands only, but got "+op.pretty(); if(expr.id()==ID_and) { if_exprt if_e(op, tmp, false_exprt()); tmp.swap(if_e); } else // ID_or { if_exprt if_e(op, true_exprt(), tmp); tmp.swap(if_e); } } expr.swap(tmp); }
exprt 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 goto_checkt::div_by_zero_check(const exprt &expr, const guardt &guard) { if (options.get_bool_option("no-div-by-zero-check")) return; if (expr.operands().size() != 2) throw expr.id_string() + " takes two arguments"; // add divison by zero subgoal exprt zero = gen_zero(expr.op1().type()); if (zero.is_nil()) throw "no zero of argument type of operator " + expr.id_string(); exprt inequality("notequal", bool_typet()); inequality.copy_to_operands(expr.op1(), zero); add_guarded_claim(inequality, "division by zero", "division-by-zero", expr.find_location(), guard); }
void goto_checkt::overflow_check(const exprt &expr, const guardt &guard) { if (!options.get_bool_option("overflow-check")) return; // first, check type if (expr.type().id() != "signedbv") return; // add overflow subgoal exprt overflow("overflow-" + expr.id_string(), bool_typet()); overflow.operands() = expr.operands(); if (expr.id() == "typecast") { if (expr.operands().size() != 1) throw "typecast takes one operand"; const typet &old_type = expr.op0().type(); unsigned new_width = atoi(expr.type().width().c_str()); unsigned old_width = atoi(old_type.width().c_str()); if (old_type.id() == "unsignedbv") new_width--; if (new_width >= old_width) return; overflow.id(overflow.id_string() + "-" + i2string(new_width)); } overflow.make_not(); add_guarded_claim(overflow, "arithmetic overflow on " + expr.id_string(), "overflow", expr.find_location(), guard); }
void goto_checkt::pointer_rel_check(const exprt &expr, const guardt &guard) { if (expr.operands().size() != 2) throw expr.id_string() + " takes one argument"; if (expr.op0().type().id() == "pointer" && expr.op1().type().id() == "pointer") { // add same-object subgoal if (!options.get_bool_option("no-pointer-check")) { exprt same_object("same-object", bool_typet()); same_object.copy_to_operands(expr.op0(), expr.op1()); add_guarded_claim(same_object, "same object violation", "pointer", expr.find_location(), guard); } } }
void rd_range_domaint::assign( const namespacet &ns, locationt from, const exprt &lhs, const mp_integer &size) { if(lhs.id()==ID_typecast) assign(ns, from, to_typecast_expr(lhs).op(), size); else if(lhs.id()==ID_if) assign_if(ns, from, to_if_expr(lhs), size); else if(lhs.id()==ID_dereference) assign_dereference(ns, from, to_dereference_expr(lhs), size); else if(lhs.id()==ID_byte_extract_little_endian || lhs.id()==ID_byte_extract_big_endian) assign_byte_extract(ns, from, to_byte_extract_expr(lhs), size); else if(lhs.id()==ID_symbol || lhs.id()==ID_index || lhs.id()==ID_member) assign(ns, from, lhs, compute_pointer_offset(ns, lhs), size); else throw "assignment to `"+lhs.id_string()+"' not handled"; }
void goto_checkt::nan_check(const exprt &expr, const guardt &guard) { if (!options.get_bool_option("nan-check")) return; // first, check type if (expr.type().id() != "floatbv") return; if (expr.id() != "+" && expr.id() != "*" && expr.id() != "/" && expr.id() != "-") return; // add nan subgoal exprt isnan("isnan", bool_typet()); isnan.copy_to_operands(expr); isnan.make_not(); add_guarded_claim(isnan, "NaN on " + expr.id_string(), "NaN", expr.find_location(), 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); }
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::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); }
value_set_dereferencet::valuet value_set_dereferencet::build_reference_to( const exprt &what, const modet mode, const exprt &pointer_expr, const guardt &guard) { const typet &dereference_type= ns.follow(pointer_expr.type()).subtype(); if(what.id()==ID_unknown || what.id()==ID_invalid) { invalid_pointer(pointer_expr, guard); return valuet(); } if(what.id()!=ID_object_descriptor) throw "unknown points-to: "+what.id_string(); const object_descriptor_exprt &o=to_object_descriptor_expr(what); const exprt &root_object=o.root_object(); const exprt &object=o.object(); #if 0 std::cout << "O: " << from_expr(ns, "", root_object) << '\n'; #endif valuet result; if(root_object.id()=="NULL-object") { if(options.get_bool_option("pointer-check")) { guardt tmp_guard(guard); if(o.offset().is_zero()) { tmp_guard.add(null_pointer(pointer_expr)); dereference_callback.dereference_failure( "pointer dereference", "NULL pointer", tmp_guard); } else { tmp_guard.add(null_object(pointer_expr)); dereference_callback.dereference_failure( "pointer dereference", "NULL plus offset pointer", tmp_guard); } } } else if(root_object.id()==ID_dynamic_object) { // const dynamic_object_exprt &dynamic_object= // to_dynamic_object_expr(root_object); // the object produced by malloc exprt malloc_object= ns.lookup(CPROVER_PREFIX "malloc_object").symbol_expr(); exprt is_malloc_object=same_object(pointer_expr, malloc_object); // constraint that it actually is a dynamic object exprt dynamic_object_expr(ID_dynamic_object, bool_typet()); dynamic_object_expr.copy_to_operands(pointer_expr); // this is also our guard result.pointer_guard=dynamic_object_expr; // can't remove here, turn into *p result.value=dereference_exprt(pointer_expr, dereference_type); if(options.get_bool_option("pointer-check")) { // if(!dynamic_object.valid().is_true()) { // check if it is still alive guardt tmp_guard(guard); tmp_guard.add(deallocated(pointer_expr, ns)); dereference_callback.dereference_failure( "pointer dereference", "dynamic object deallocated", tmp_guard); } if(options.get_bool_option("bounds-check")) { if(!o.offset().is_zero()) { // check lower bound guardt tmp_guard(guard); tmp_guard.add(is_malloc_object); tmp_guard.add( dynamic_object_lower_bound( pointer_expr, ns, nil_exprt())); dereference_callback.dereference_failure( "pointer dereference", "dynamic object lower bound", tmp_guard); } { // check upper bound // we check SAME_OBJECT(__CPROVER_malloc_object, p) && // POINTER_OFFSET(p)+size>__CPROVER_malloc_size guardt tmp_guard(guard); tmp_guard.add(is_malloc_object); tmp_guard.add( dynamic_object_upper_bound( pointer_expr, dereference_type, ns, size_of_expr(dereference_type, ns))); dereference_callback.dereference_failure( "pointer dereference", "dynamic object upper bound", tmp_guard); } } } } else if(root_object.id()==ID_integer_address) { // This is stuff like *((char *)5). // This is turned into an access to __CPROVER_memory[...]. if(language_mode==ID_java) { result.value=nil_exprt(); return result; } const symbolt &memory_symbol=ns.lookup(CPROVER_PREFIX "memory"); exprt symbol_expr=symbol_exprt(memory_symbol.name, memory_symbol.type); if(base_type_eq( ns.follow(memory_symbol.type).subtype(), dereference_type, ns)) { // Types match already, what a coincidence! // We can use an index expression. exprt index_expr=index_exprt(symbol_expr, pointer_offset(pointer_expr)); index_expr.type()=ns.follow(memory_symbol.type).subtype(); result.value=index_expr; } else if(dereference_type_compare( ns.follow(memory_symbol.type).subtype(), dereference_type)) { exprt index_expr=index_exprt(symbol_expr, pointer_offset(pointer_expr)); index_expr.type()=ns.follow(memory_symbol.type).subtype(); result.value=typecast_exprt(index_expr, dereference_type); } else { // We need to use byte_extract. // Won't do this without a commitment to an endianness. if(config.ansi_c.endianness==configt::ansi_ct::endiannesst::NO_ENDIANNESS) { } else { exprt byte_extract(byte_extract_id(), dereference_type); byte_extract.copy_to_operands( symbol_expr, pointer_offset(pointer_expr)); result.value=byte_extract; } } } else { // something generic -- really has to be a symbol address_of_exprt object_pointer(object); if(o.offset().is_zero()) { equal_exprt equality(pointer_expr, object_pointer); if(ns.follow(equality.lhs().type())!=ns.follow(equality.rhs().type())) equality.lhs().make_typecast(equality.rhs().type()); result.pointer_guard=equality; } else { result.pointer_guard=same_object(pointer_expr, object_pointer); } guardt tmp_guard(guard); tmp_guard.add(result.pointer_guard); valid_check(object, tmp_guard, mode); const typet &object_type=ns.follow(object.type()); const exprt &root_object=o.root_object(); const typet &root_object_type=ns.follow(root_object.type()); exprt root_object_subexpression=root_object; if(dereference_type_compare(object_type, dereference_type) && o.offset().is_zero()) { // The simplest case: types match, and offset is zero! // This is great, we are almost done. result.value=object; if(object_type!=ns.follow(dereference_type)) result.value.make_typecast(dereference_type); } else if(root_object_type.id()==ID_array && dereference_type_compare( root_object_type.subtype(), dereference_type)) { // We have an array with a subtype that matches // the dereferencing type. // We will require well-alignedness! exprt offset; // this should work as the object is essentially the root object if(o.offset().is_constant()) offset=o.offset(); else offset=pointer_offset(pointer_expr); exprt adjusted_offset; // are we doing a byte? mp_integer element_size= dereference_type.id()==ID_empty? pointer_offset_size(char_type(), ns): pointer_offset_size(dereference_type, ns); if(element_size==1) { // no need to adjust offset adjusted_offset=offset; } else if(element_size<=0) { throw "unknown or invalid type size of:\n"+dereference_type.pretty(); } else { exprt element_size_expr= from_integer(element_size, offset.type()); adjusted_offset=binary_exprt( offset, ID_div, element_size_expr, offset.type()); // TODO: need to assert well-alignedness } index_exprt index_expr= index_exprt(root_object, adjusted_offset, root_object_type.subtype()); bounds_check(index_expr, tmp_guard); result.value=index_expr; if(ns.follow(result.value.type())!=ns.follow(dereference_type)) result.value.make_typecast(dereference_type); } else if(get_subexpression_at_offset( root_object_subexpression, o.offset(), dereference_type, ns)) { // Successfully found a member, array index, or combination thereof // that matches the desired type and offset: result.value=root_object_subexpression; } else { // we extract something from the root object result.value=o.root_object(); // this is relative to the root object const exprt offset=pointer_offset(pointer_expr); if(memory_model(result.value, dereference_type, tmp_guard, offset)) { // ok, done } else { if(options.get_bool_option("pointer-check")) { std::string msg="memory model not applicable (got `"; msg+=from_type(ns, "", result.value.type()); msg+="', expected `"; msg+=from_type(ns, "", dereference_type); msg+="')"; dereference_callback.dereference_failure( "pointer dereference", msg, tmp_guard); } return valuet(); // give up, no way that this is ok } } } return result; }
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()+"'"; }
void value_sett::get_value_set_rec( const exprt &expr, object_mapt &dest, const std::string &suffix, const typet &original_type, const namespacet &ns) const { #if 0 std::cout << "GET_VALUE_SET_REC EXPR: " << from_expr(ns, "", expr) << "\n"; std::cout << "GET_VALUE_SET_REC SUFFIX: " << suffix << std::endl; #endif const typet &expr_type=ns.follow(expr.type()); if(expr.id()==ID_unknown || expr.id()==ID_invalid) { insert(dest, exprt(ID_unknown, original_type)); } else if(expr.id()==ID_index) { assert(expr.operands().size()==2); const typet &type=ns.follow(expr.op0().type()); assert(type.id()==ID_array || type.id()==ID_incomplete_array); get_value_set_rec(expr.op0(), dest, "[]"+suffix, original_type, ns); } else if(expr.id()==ID_member) { assert(expr.operands().size()==1); const typet &type=ns.follow(expr.op0().type()); assert(type.id()==ID_struct || type.id()==ID_union || type.id()==ID_incomplete_struct || type.id()==ID_incomplete_union); const std::string &component_name= expr.get_string(ID_component_name); get_value_set_rec(expr.op0(), dest, "."+component_name+suffix, original_type, ns); } else if(expr.id()==ID_symbol) { irep_idt identifier=to_symbol_expr(expr).get_identifier(); // is it a pointer, integer, array or struct? if(expr_type.id()==ID_pointer || expr_type.id()==ID_signedbv || expr_type.id()==ID_unsignedbv || expr_type.id()==ID_struct || expr_type.id()==ID_union || expr_type.id()==ID_array) { // look it up valuest::const_iterator v_it= values.find(id2string(identifier)+suffix); // try first component name as suffix if not yet found if(v_it==values.end() && (expr_type.id()==ID_struct || expr_type.id()==ID_union)) { const struct_union_typet &struct_union_type= to_struct_union_type(expr_type); const std::string first_component_name= struct_union_type.components().front().get_string(ID_name); v_it=values.find( id2string(identifier)+"."+first_component_name+suffix); } // not found? try without suffix if(v_it==values.end()) v_it=values.find(identifier); if(v_it!=values.end()) make_union(dest, v_it->second.object_map); else insert(dest, exprt(ID_unknown, original_type)); } else insert(dest, exprt(ID_unknown, original_type)); } else if(expr.id()==ID_if) { if(expr.operands().size()!=3) throw "if takes three operands"; get_value_set_rec(expr.op1(), dest, suffix, original_type, ns); get_value_set_rec(expr.op2(), dest, suffix, original_type, ns); } else if(expr.id()==ID_address_of) { if(expr.operands().size()!=1) throw expr.id_string()+" expected to have one operand"; get_reference_set(expr.op0(), dest, ns); } else if(expr.id()==ID_dereference) { object_mapt reference_set; get_reference_set(expr, reference_set, ns); const object_map_dt &object_map=reference_set.read(); if(object_map.begin()==object_map.end()) insert(dest, exprt(ID_unknown, original_type)); else { for(object_map_dt::const_iterator it1=object_map.begin(); it1!=object_map.end(); it1++) { const exprt &object=object_numbering[it1->first]; get_value_set_rec(object, dest, suffix, original_type, ns); } } } else if(expr.id()=="reference_to") { // old stuff, will go away object_mapt reference_set; get_reference_set(expr, reference_set, ns); const object_map_dt &object_map=reference_set.read(); if(object_map.begin()==object_map.end()) insert(dest, exprt(ID_unknown, original_type)); else { for(object_map_dt::const_iterator it=object_map.begin(); it!=object_map.end(); it++) { const exprt &object=object_numbering[it->first]; get_value_set_rec(object, dest, suffix, original_type, ns); } } } else if(expr.is_constant()) { // check if NULL if(expr.get(ID_value)==ID_NULL && expr_type.id()==ID_pointer) { insert(dest, exprt("NULL-object", expr_type.subtype()), 0); } else if(expr_type.id()==ID_unsignedbv || expr_type.id()==ID_signedbv) { // an integer constant got turned into a pointer insert(dest, exprt(ID_integer_address, unsigned_char_type())); } else insert(dest, exprt(ID_unknown, original_type)); } else if(expr.id()==ID_typecast) { if(expr.operands().size()!=1) throw "typecast takes one operand"; // let's see what gets converted to what const typet &op_type=ns.follow(expr.op0().type()); if(op_type.id()==ID_pointer) { // pointer-to-pointer -- we just ignore these get_value_set_rec(expr.op0(), dest, suffix, original_type, ns); } else if(op_type.id()==ID_unsignedbv || op_type.id()==ID_signedbv) { // integer-to-pointer if(expr.op0().is_zero()) insert(dest, exprt("NULL-object", expr_type.subtype()), 0); else { // see if we have something for the integer object_mapt tmp; get_value_set_rec(expr.op0(), tmp, suffix, original_type, ns); if(tmp.read().size()==0) { // if not, throw in integer insert(dest, exprt(ID_integer_address, unsigned_char_type())); } else if(tmp.read().size()==1 && object_numbering[tmp.read().begin()->first].id()==ID_unknown) { // if not, throw in integer insert(dest, exprt(ID_integer_address, unsigned_char_type())); } else { // use as is dest.write().insert(tmp.read().begin(), tmp.read().end()); } } } else insert(dest, exprt(ID_unknown, original_type)); } else if(expr.id()==ID_plus || expr.id()==ID_minus) { if(expr.operands().size()<2) throw expr.id_string()+" expected to have at least two operands"; object_mapt pointer_expr_set; mp_integer i; bool i_is_set=false; // special case for pointer+integer if(expr.operands().size()==2 && expr_type.id()==ID_pointer) { exprt ptr_operand; if(expr.op0().type().id()!=ID_pointer && expr.op0().is_constant()) { i_is_set=!to_integer(expr.op0(), i); ptr_operand=expr.op1(); } else { i_is_set=!to_integer(expr.op1(), i); ptr_operand=expr.op0(); } if(i_is_set) { i*=pointer_offset_size(ptr_operand.type().subtype(), ns); if(expr.id()==ID_minus) i.negate(); } get_value_set_rec( ptr_operand, pointer_expr_set, "", ptr_operand.type(), ns); } else { // we get the points-to for all operands, even integers forall_operands(it, expr) { get_value_set_rec( *it, pointer_expr_set, "", it->type(), ns); } } for(object_map_dt::const_iterator it=pointer_expr_set.read().begin(); it!=pointer_expr_set.read().end(); it++) { objectt object=it->second; // adjust by offset if(object.offset_is_zero() && i_is_set) object.offset=i; else object.offset_is_set=false; insert(dest, it->first, object); } }
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::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_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); } } }
void goto_inlinet::expand_function_call( goto_programt &dest, goto_programt::targett &target, const exprt &lhs, const exprt &function, const exprt::operandst &arguments, const exprt &constrain, bool full) { // look it up if(function.id()!="symbol") { err_location(function); throw "function_call expects symbol as function operand, " "but got `"+function.id_string()+"'"; } const irep_idt &identifier=function.identifier(); // see if we are already expanding it if(recursion_set.find(identifier)!=recursion_set.end()) { if(!full) { target++; return; // simply ignore, we don't do full inlining, it's ok } // it's really recursive. Uh. Buh. Give up. err_location(function); warning("recursion is ignored"); target->make_skip(); target++; return; } goto_functionst::function_mapt::iterator m_it= goto_functions.function_map.find(identifier); if(m_it==goto_functions.function_map.end()) { err_location(function); str << "failed to find function `" << identifier << "'"; throw 0; } goto_functiont &f=m_it->second; // see if we need to inline this if(!full) { if(!f.body_available || (!f.is_inlined() && f.body.instructions.size() > smallfunc_limit)) { target++; return; } } if(f.body_available) { inlined_funcs.insert(identifier.as_string()); for (std::set<std::string>::const_iterator it2 = f.inlined_funcs.begin(); it2 != f.inlined_funcs.end(); it2++) { inlined_funcs.insert(*it2); } recursion_sett::iterator recursion_it= recursion_set.insert(identifier).first; goto_programt tmp2; tmp2.copy_from(f.body); assert(tmp2.instructions.back().is_end_function()); tmp2.instructions.back().type=LOCATION; replace_return(tmp2, lhs, constrain); goto_programt tmp; parameter_assignments(tmp2.instructions.front().location, f.type, arguments, tmp); tmp.destructive_append(tmp2); // set local variables Forall_goto_program_instructions(it, tmp) it->local_variables.insert(target->local_variables.begin(), target->local_variables.end()); if(f.type.hide()) { const locationt &new_location=function.find_location(); Forall_goto_program_instructions(it, tmp) { if(new_location.is_not_nil()) { // can't just copy, e.g., due to comments field it->location.id(""); // not NIL it->location.set_file(new_location.get_file()); it->location.set_line(new_location.get_line()); it->location.set_column(new_location.get_column()); it->location.set_function(new_location.get_function()); } } } // do this recursively goto_inline_rec(tmp, full); // set up location instruction for function call target->type=LOCATION; target->code = expr2tc(); goto_programt::targett next_target(target); next_target++; dest.instructions.splice(next_target, tmp.instructions); target=next_target; recursion_set.erase(recursion_it); }
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 abstract_expression( const predicatest &predicates, exprt &expr, const namespacet &ns) { if(expr.type().id()!=ID_bool) throw "abstract_expression expects expression of type Boolean"; simplify(expr, ns); if(is_valid(expr, ns)) { // If expr is valid, we can abstract it as 'true' expr.make_true(); } else if(is_unsatisfiable(expr, ns)) { // If expr is unsatisfiable, we can abstract it as 'false' expr.make_false(); } else if(expr.id()==ID_and || expr.id()==ID_or || expr.id()==ID_implies || expr.id()==ID_xor) { Forall_operands(it, expr) abstract_expression(predicates, *it, ns); } else if(expr.id()==ID_not) { assert(expr.operands().size()==1); abstract_expression(predicates, expr.op0(), ns); // remove double negation if(expr.op0().id()==ID_not && expr.op0().operands().size()==1) { exprt tmp; tmp.swap(expr.op0().op0()); expr.swap(tmp); } } else if(expr.id()==ID_if) { assert(expr.operands().size()==3); Forall_operands(it, expr) abstract_expression(predicates, *it, ns); exprt true_expr(ID_and, bool_typet()); true_expr.copy_to_operands(expr.op0(), expr.op1()); exprt false_expr(ID_and, bool_typet()); false_expr.copy_to_operands(gen_not(expr.op0()), expr.op2()); exprt or_expr(ID_or, bool_typet()); or_expr.move_to_operands(true_expr, false_expr); expr.swap(or_expr); } else if(expr.id()==ID_equal || expr.id()==ID_notequal) { if(expr.operands().size()!=2) throw expr.id_string()+" takes two operands"; // Is it equality on Booleans? if(expr.op0().type().id()==ID_bool && expr.op1().type().id()==ID_bool) { // leave it in Forall_operands(it, expr) abstract_expression(predicates, *it, ns); } else // other types, make it a predicate { if(has_non_boolean_if(expr)) { lift_if(expr); abstract_expression(predicates, expr, ns); } else make_it_a_predicate(predicates, expr, ns); } } else if(expr.is_constant()) { // leave it as is } else if(has_non_boolean_if(expr)) { lift_if(expr); abstract_expression(predicates, expr, ns); } else { make_it_a_predicate(predicates, expr, ns); } }
void cvc_convt::convert_address_of_rec(const exprt &expr) { if(expr.id()==ID_symbol || expr.id()==ID_constant || expr.id()==ID_string_constant) { out << "(# object:=" << pointer_logic.add_object(expr) << ", offset:=" << bin_zero(config.ansi_c.pointer_width) << " #)"; } else if(expr.id()==ID_index) { if(expr.operands().size()!=2) throw "index takes two operands"; const exprt &array=expr.op0(); const exprt &index=expr.op1(); if(index.is_zero()) { if(array.type().id()==ID_pointer) convert_expr(array); else if(array.type().id()==ID_array) convert_address_of_rec(array); else assert(false); } else { out << "(LET P: "; out << cvc_pointer_type(); out << " = "; if(array.type().id()==ID_pointer) convert_expr(array); else if(array.type().id()==ID_array) convert_address_of_rec(array); else assert(false); out << " IN P WITH .offset:=BVPLUS(" << config.ansi_c.pointer_width << ", P.offset, "; convert_expr(index); out << "))"; } } else if(expr.id()==ID_member) { if(expr.operands().size()!=1) throw "member takes one operand"; const exprt &struct_op=expr.op0(); out << "(LET P: "; out << cvc_pointer_type(); out << " = "; convert_address_of_rec(struct_op); const irep_idt &component_name= to_member_expr(expr).get_component_name(); mp_integer offset=member_offset( to_struct_type(struct_op.type()), component_name, ns); typet index_type(ID_unsignedbv); index_type.set(ID_width, config.ansi_c.pointer_width); exprt index=from_integer(offset, index_type); out << " IN P WITH .offset:=BVPLUS(" << config.ansi_c.pointer_width << ", P.offset, "; convert_expr(index); out << "))"; } else throw "don't know how to take address of: "+expr.id_string(); }
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); }
literalt boolbvt::convert_overflow(const exprt &expr) { const exprt::operandst &operands=expr.operands(); if(expr.id()==ID_overflow_plus || expr.id()==ID_overflow_minus) { if(operands.size()!=2) throw "operator "+expr.id_string()+" takes two operands"; const bvt &bv0=convert_bv(operands[0]); const bvt &bv1=convert_bv(operands[1]); if(bv0.size()!=bv1.size()) return SUB::convert_rest(expr); bv_utilst::representationt rep= expr.op0().type().id()==ID_signedbv?bv_utilst::SIGNED: bv_utilst::UNSIGNED; return expr.id()==ID_overflow_minus? bv_utils.overflow_sub(bv0, bv1, rep): bv_utils.overflow_add(bv0, bv1, rep); } else if(expr.id()==ID_overflow_mult) { if(operands.size()!=2) throw "operator "+expr.id_string()+" takes two operands"; if(operands[0].type().id()!=ID_unsignedbv && operands[0].type().id()!=ID_signedbv) return SUB::convert_rest(expr); bvt bv0=convert_bv(operands[0]); bvt bv1=convert_bv(operands[1]); if(bv0.size()!=bv1.size()) throw "operand size mismatch on overflow-*"; bv_utilst::representationt rep= operands[0].type().id()==ID_signedbv?bv_utilst::SIGNED: bv_utilst::UNSIGNED; if(operands[0].type()!=operands[1].type()) throw "operand type mismatch on overflow-*"; assert(bv0.size()==bv1.size()); unsigned old_size=bv0.size(); unsigned new_size=old_size*2; // sign/zero extension bv0=bv_utils.extension(bv0, new_size, rep); bv1=bv_utils.extension(bv1, new_size, rep); bvt result=bv_utils.multiplier(bv0, bv1, rep); if(rep==bv_utilst::UNSIGNED) { bvt bv_overflow; bv_overflow.reserve(old_size); // get top result bits for(unsigned i=old_size; i<result.size(); i++) bv_overflow.push_back(result[i]); return prop.lor(bv_overflow); } else { bvt bv_overflow; bv_overflow.reserve(old_size); // get top result bits, plus one more assert(old_size!=0); for(unsigned i=old_size-1; i<result.size(); i++) bv_overflow.push_back(result[i]); // these need to be either all 1's or all 0's literalt all_one=prop.land(bv_overflow); literalt all_zero=prop.lnot(prop.lor(bv_overflow)); return prop.lnot(prop.lor(all_one, all_zero)); } } else if(expr.id()==ID_overflow_unary_minus) { if(operands.size()!=1) throw "operator "+expr.id_string()+" takes one operand"; const bvt &bv=convert_bv(operands[0]); return bv_utils.overflow_negate(bv); } else if(has_prefix(expr.id_string(), "overflow-typecast-")) { unsigned bits=atoi(expr.id().c_str()+18); const exprt::operandst &operands=expr.operands(); if(operands.size()!=1) throw "operator "+expr.id_string()+" takes one operand"; const exprt &op=operands[0]; const bvt &bv=convert_bv(op); if(bits>=bv.size() || bits==0) throw "overflow-typecast got wrong number of bits"; // signed or unsigned? if(op.type().id()==ID_signedbv) { bvt tmp_bv; for(unsigned i=bits; i<bv.size(); i++) tmp_bv.push_back(prop.lxor(bv[bits-1], bv[i])); return prop.lor(tmp_bv); } else { bvt tmp_bv; for(unsigned i=bits; i<bv.size(); i++) tmp_bv.push_back(bv[i]); return prop.lor(tmp_bv); } } return SUB::convert_rest(expr); }
exprt goto_symext::address_arithmetic( const exprt &expr, statet &state, guardt &guard, bool keep_array) { exprt result; if(expr.id()==ID_byte_extract_little_endian || expr.id()==ID_byte_extract_big_endian) { // address_of(byte_extract(op, offset, t)) is // address_of(op) + offset with adjustments for arrays const byte_extract_exprt &be=to_byte_extract_expr(expr); // recursive call result=address_arithmetic(be.op(), state, guard, keep_array); if(ns.follow(be.op().type()).id()==ID_array && result.id()==ID_address_of) { address_of_exprt &a=to_address_of_expr(result); // turn &a of type T[i][j] into &(a[0][0]) for(const typet *t=&(ns.follow(a.type().subtype())); t->id()==ID_array && !base_type_eq(expr.type(), *t, ns); t=&(ns.follow(*t).subtype())) a.object()=index_exprt(a.object(), from_integer(0, index_type())); } // do (expr.type() *)(((char *)op)+offset) result=typecast_exprt(result, pointer_typet(char_type())); // there could be further dereferencing in the offset exprt offset=be.offset(); dereference_rec(offset, state, guard, false); result=plus_exprt(result, offset); // treat &array as &array[0] const typet &expr_type=ns.follow(expr.type()); pointer_typet dest_type; if(expr_type.id()==ID_array && !keep_array) dest_type.subtype()=expr_type.subtype(); else dest_type.subtype()=expr_type; result=typecast_exprt(result, dest_type); } else if(expr.id()==ID_index || expr.id()==ID_member) { object_descriptor_exprt ode; ode.build(expr, ns); byte_extract_exprt be(byte_extract_id()); be.type()=expr.type(); be.op()=ode.root_object(); be.offset()=ode.offset(); // recursive call result=address_arithmetic(be, state, guard, keep_array); do_simplify(result); } else if(expr.id()==ID_dereference) { // ANSI-C guarantees &*p == p no matter what p is, // even if it's complete garbage // just grab the pointer, but be wary of further dereferencing // in the pointer itself result=to_dereference_expr(expr).pointer(); dereference_rec(result, state, guard, false); } else if(expr.id()==ID_if) { if_exprt if_expr=to_if_expr(expr); // the condition is not an address dereference_rec(if_expr.cond(), state, guard, false); // recursive call if_expr.true_case()= address_arithmetic(if_expr.true_case(), state, guard, keep_array); if_expr.false_case()= address_arithmetic(if_expr.false_case(), state, guard, keep_array); result=if_expr; } else if(expr.id()==ID_symbol || expr.id()==ID_string_constant || expr.id()==ID_label || expr.id()==ID_array) { // give up, just dereference result=expr; dereference_rec(result, state, guard, false); // turn &array into &array[0] if(ns.follow(result.type()).id()==ID_array && !keep_array) result=index_exprt(result, from_integer(0, index_type())); // handle field-sensitive SSA symbol mp_integer offset=0; if(expr.id()==ID_symbol && expr.get_bool(ID_C_SSA_symbol)) { offset=compute_pointer_offset(expr, ns); assert(offset>=0); } if(offset>0) { byte_extract_exprt be(byte_extract_id()); be.type()=expr.type(); be.op()=to_ssa_expr(expr).get_l1_object(); be.offset()=from_integer(offset, index_type()); result=address_arithmetic(be, state, guard, keep_array); do_simplify(result); } else result=address_of_exprt(result); } else throw "goto_symext::address_arithmetic does not handle "+expr.id_string(); const typet &expr_type=ns.follow(expr.type()); assert((expr_type.id()==ID_array && !keep_array) || base_type_eq(pointer_typet(expr_type), result.type(), ns)); return result; }