bvt boolbvt::convert_with(const exprt &expr) { if(expr.operands().size()<3) { error().source_location=expr.find_source_location(); error() << "with takes at least three operands" << eom; throw 0; } if((expr.operands().size()%2)!=1) { error().source_location=expr.find_source_location(); error() << "with takes an odd number of operands" << eom; throw 0; } bvt bv=convert_bv(expr.op0()); std::size_t width=boolbv_width(expr.type()); if(width==0) return conversion_failed(expr); if(bv.size()!=width) { error().source_location=expr.find_source_location(); error() << "unexpected operand 0 width" << eom; throw 0; } bvt prev_bv; prev_bv.resize(width); const exprt::operandst &ops=expr.operands(); for(std::size_t op_no=1; op_no<ops.size(); op_no+=2) { bv.swap(prev_bv); convert_with(expr.op0().type(), ops[op_no], ops[op_no+1], prev_bv, bv); } return bv; }
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); } } }
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 goto_convertt::do_function_call( const exprt &lhs, const exprt &function, const exprt::operandst &arguments, goto_programt &dest) { // make it all side effect free exprt new_lhs=lhs, new_function=function; exprt::operandst new_arguments=arguments; if(!new_lhs.is_nil()) clean_expr(new_lhs, dest); clean_expr(new_function, dest); // the arguments of __noop do not get evaluated if(new_function.id()==ID_symbol && to_symbol_expr(new_function).get_identifier()=="__noop") { new_arguments.clear(); } Forall_expr(it, new_arguments) clean_expr(*it, dest); // split on the function if(new_function.id()==ID_if) { do_function_call_if(new_lhs, to_if_expr(new_function), new_arguments, dest); } else if(new_function.id()==ID_symbol) { do_function_call_symbol(new_lhs, to_symbol_expr(new_function), new_arguments, dest); } else if(new_function.id()=="NULL-object") { } else if(new_function.id()==ID_dereference || new_function.id()=="virtual_function") { do_function_call_other(new_lhs, new_function, new_arguments, dest); } else { error().source_location=function.find_source_location(); error() << "unexpected function argument: " << new_function.id() << eom; throw 0; } }
void c_typecheck_baset::implicit_typecast( exprt &expr, const typet &dest_type) { c_typecastt c_typecast(*this); typet src_type=expr.type(); c_typecast.implicit_typecast(expr, dest_type); for(std::list<std::string>::const_iterator it=c_typecast.errors.begin(); it!=c_typecast.errors.end(); it++) { error().source_location=expr.find_source_location(); error() << "in expression `" << to_string(expr) << "':\n" << "conversion from `" << to_string(src_type) << "' to `" << to_string(dest_type) << "': " << *it << eom; } if(!c_typecast.errors.empty()) throw 0; // give up for(std::list<std::string>::const_iterator it=c_typecast.warnings.begin(); it!=c_typecast.warnings.end(); it++) { warning().source_location=expr.find_source_location(); warning() << "warning: conversion from `" << to_string(src_type) << "' to `" << to_string(dest_type) << "': " << *it << eom; } }
exprt c_typecheck_baset::do_initializer_list( const exprt &value, const typet &type, bool force_constant) { assert(value.id()==ID_initializer_list); const typet &full_type=follow(type); exprt result; if(full_type.id()==ID_struct || full_type.id()==ID_union || full_type.id()==ID_vector) { // start with zero everywhere result= zero_initializer( type, value.source_location(), *this, get_message_handler()); } else if(full_type.id()==ID_array) { if(to_array_type(full_type).size().is_nil()) { // start with empty array result=exprt(ID_array, full_type); result.add_source_location()=value.source_location(); } else { // start with zero everywhere result= zero_initializer( type, value.source_location(), *this, get_message_handler()); } // 6.7.9, 14: An array of character type may be initialized by a character // string literal or UTF-8 string literal, optionally enclosed in braces. if(value.operands().size()>=1 && value.op0().id()==ID_string_constant && (full_type.subtype().id()==ID_signedbv || full_type.subtype().id()==ID_unsignedbv) && full_type.subtype().get(ID_width)==char_type().get(ID_width)) { if(value.operands().size()>1) { warning().source_location=value.find_source_location(); warning() << "ignoring excess initializers" << eom; } return do_initializer_rec(value.op0(), type, force_constant); } } else { // The initializer for a scalar shall be a single expression, // * optionally enclosed in braces. * if(value.operands().size()==1) return do_initializer_rec(value.op0(), type, force_constant); err_location(value); error() << "cannot initialize `" << to_string(full_type) << "' with an initializer list" << eom; throw 0; } designatort current_designator; designator_enter(type, current_designator); forall_operands(it, value) { do_designated_initializer( result, current_designator, *it, force_constant); // increase designator -- might go up increment_designator(current_designator); }
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_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::float_overflow_check( const exprt &expr, const guardt &guard) { if(!enable_float_overflow_check) return; // First, check type. const typet &type=ns.follow(expr.type()); if(type.id()!=ID_floatbv) return; // add overflow subgoal if(expr.id()==ID_typecast) { // Can overflow if casting from larger // to smaller type. assert(expr.operands().size()==1); if(ns.follow(expr.op0().type()).id()==ID_floatbv) { // float-to-float unary_exprt op0_inf(ID_isinf, expr.op0(), bool_typet()); unary_exprt new_inf(ID_isinf, expr, bool_typet()); or_exprt overflow_check(op0_inf, not_exprt(new_inf)); add_guarded_claim( overflow_check, "arithmetic overflow on floating-point typecast", "overflow", expr.find_source_location(), expr, guard); } else { // non-float-to-float unary_exprt new_inf(ID_isinf, expr, bool_typet()); add_guarded_claim( not_exprt(new_inf), "arithmetic overflow on floating-point typecast", "overflow", expr.find_source_location(), expr, guard); } return; } else if(expr.id()==ID_div) { assert(expr.operands().size()==2); // Can overflow if dividing by something small unary_exprt new_inf(ID_isinf, expr, bool_typet()); unary_exprt op0_inf(ID_isinf, expr.op0(), bool_typet()); or_exprt overflow_check(op0_inf, not_exprt(new_inf)); add_guarded_claim( overflow_check, "arithmetic overflow on floating-point division", "overflow", expr.find_source_location(), expr, guard); return; } else if(expr.id()==ID_mod) { // Can't overflow return; } else if(expr.id()==ID_unary_minus) { // Can't overflow return; } else if(expr.id()==ID_plus || expr.id()==ID_mult || expr.id()==ID_minus) { if(expr.operands().size()==2) { // Can overflow unary_exprt new_inf(ID_isinf, expr, bool_typet()); unary_exprt op0_inf(ID_isinf, expr.op0(), bool_typet()); unary_exprt op1_inf(ID_isinf, expr.op1(), bool_typet()); or_exprt overflow_check(op0_inf, op1_inf, not_exprt(new_inf)); std::string kind= expr.id()==ID_plus?"addition": expr.id()==ID_minus?"subtraction": expr.id()==ID_mult?"multiplication":""; add_guarded_claim( overflow_check, "arithmetic overflow on floating-point "+kind, "overflow", expr.find_source_location(), expr, guard); return; } else if(expr.operands().size()>=3) { assert(expr.id()!=ID_minus); // break up exprt tmp=make_binary(expr); float_overflow_check(tmp, guard); return; } } }
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::conversion_check( const exprt &expr, const guardt &guard) { if(!enable_conversion_check) return; // First, check type. const typet &type=ns.follow(expr.type()); if(type.id()!=ID_signedbv && type.id()!=ID_unsignedbv) return; if(expr.id()==ID_typecast) { // conversion to signed int may overflow if(expr.operands().size()!=1) throw "typecast takes one operand"; const typet &old_type=ns.follow(expr.op0().type()); if(type.id()==ID_signedbv) { std::size_t new_width=to_signedbv_type(type).get_width(); if(old_type.id()==ID_signedbv) // signed -> signed { std::size_t old_width=to_signedbv_type(old_type).get_width(); if(new_width>=old_width) return; // always ok binary_relation_exprt no_overflow_upper(ID_le); no_overflow_upper.lhs()=expr.op0(); no_overflow_upper.rhs()=from_integer(power(2, new_width-1)-1, old_type); binary_relation_exprt no_overflow_lower(ID_ge); no_overflow_lower.lhs()=expr.op0(); no_overflow_lower.rhs()=from_integer(-power(2, new_width-1), old_type); add_guarded_claim( and_exprt(no_overflow_lower, no_overflow_upper), "arithmetic overflow on signed type conversion", "overflow", expr.find_source_location(), expr, guard); } else if(old_type.id()==ID_unsignedbv) // unsigned -> signed { std::size_t old_width=to_unsignedbv_type(old_type).get_width(); if(new_width>=old_width+1) return; // always ok binary_relation_exprt no_overflow_upper(ID_le); no_overflow_upper.lhs()=expr.op0(); no_overflow_upper.rhs()=from_integer(power(2, new_width-1)-1, old_type); add_guarded_claim( no_overflow_upper, "arithmetic overflow on unsigned to signed type conversion", "overflow", expr.find_source_location(), expr, guard); } else if(old_type.id()==ID_floatbv) // float -> signed { // Note that the fractional part is truncated! ieee_floatt upper(to_floatbv_type(old_type)); upper.from_integer(power(2, new_width-1)); binary_relation_exprt no_overflow_upper(ID_lt); no_overflow_upper.lhs()=expr.op0(); no_overflow_upper.rhs()=upper.to_expr(); ieee_floatt lower(to_floatbv_type(old_type)); lower.from_integer(-power(2, new_width-1)-1); binary_relation_exprt no_overflow_lower(ID_gt); no_overflow_lower.lhs()=expr.op0(); no_overflow_lower.rhs()=lower.to_expr(); add_guarded_claim( and_exprt(no_overflow_lower, no_overflow_upper), "arithmetic overflow on float to signed integer type conversion", "overflow", expr.find_source_location(), expr, guard); } } else if(type.id()==ID_unsignedbv) { std::size_t new_width=to_unsignedbv_type(type).get_width(); if(old_type.id()==ID_signedbv) // signed -> unsigned { std::size_t old_width=to_signedbv_type(old_type).get_width(); if(new_width>=old_width-1) { // only need lower bound check binary_relation_exprt no_overflow_lower(ID_ge); no_overflow_lower.lhs()=expr.op0(); no_overflow_lower.rhs()=from_integer(0, old_type); add_guarded_claim( no_overflow_lower, "arithmetic overflow on signed to unsigned type conversion", "overflow", expr.find_source_location(), expr, guard); } else { // need both binary_relation_exprt no_overflow_upper(ID_le); no_overflow_upper.lhs()=expr.op0(); no_overflow_upper.rhs()=from_integer(power(2, new_width)-1, old_type); binary_relation_exprt no_overflow_lower(ID_ge); no_overflow_lower.lhs()=expr.op0(); no_overflow_lower.rhs()=from_integer(0, old_type); add_guarded_claim( and_exprt(no_overflow_lower, no_overflow_upper), "arithmetic overflow on signed to unsigned type conversion", "overflow", expr.find_source_location(), expr, guard); } } else if(old_type.id()==ID_unsignedbv) // unsigned -> unsigned { std::size_t old_width=to_unsignedbv_type(old_type).get_width(); if(new_width>=old_width) return; // always ok binary_relation_exprt no_overflow_upper(ID_le); no_overflow_upper.lhs()=expr.op0(); no_overflow_upper.rhs()=from_integer(power(2, new_width)-1, old_type); add_guarded_claim( no_overflow_upper, "arithmetic overflow on unsigned to unsigned type conversion", "overflow", expr.find_source_location(), expr, guard); } else if(old_type.id()==ID_floatbv) // float -> unsigned { // Note that the fractional part is truncated! ieee_floatt upper(to_floatbv_type(old_type)); upper.from_integer(power(2, new_width)-1); binary_relation_exprt no_overflow_upper(ID_lt); no_overflow_upper.lhs()=expr.op0(); no_overflow_upper.rhs()=upper.to_expr(); ieee_floatt lower(to_floatbv_type(old_type)); lower.from_integer(-1); binary_relation_exprt no_overflow_lower(ID_gt); no_overflow_lower.lhs()=expr.op0(); no_overflow_lower.rhs()=lower.to_expr(); add_guarded_claim( and_exprt(no_overflow_lower, no_overflow_upper), "arithmetic overflow on float to unsigned integer type conversion", "overflow", expr.find_source_location(), expr, guard); } } } }