void goto_checkt::mod_by_zero_check( const mod_exprt &expr, const guardt &guard) { if(!enable_div_by_zero_check) return; // 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(ID_notequal, bool_typet()); inequality.copy_to_operands(expr.op1(), zero); add_guarded_claim( inequality, "division by zero", "division-by-zero", expr.find_source_location(), expr, guard); }
void c_typecastt::implicit_typecast_arithmetic( exprt &expr, c_typet c_type) { typet new_type; const typet &expr_type=ns.follow(expr.type()); switch(c_type) { case PTR: if(expr_type.id()==ID_array) { new_type.id(ID_pointer); new_type.subtype()=expr_type.subtype(); break; } return; case BOOL: new_type=bool_typet(); break; case CHAR: assert(false); // should always be promoted to int case UCHAR: assert(false); // should always be promoted to int case SHORT: assert(false); // should always be promoted to int case USHORT: assert(false); // should always be promoted to int case INT: new_type=int_type(); break; case UINT: new_type=uint_type(); break; case LONG: new_type=long_int_type(); break; case ULONG: new_type=long_uint_type(); break; case LONGLONG: new_type=long_long_int_type(); break; case ULONGLONG: new_type=long_long_uint_type(); break; case SINGLE: new_type=float_type(); break; case DOUBLE: new_type=double_type(); break; case LONGDOUBLE: new_type=long_double_type(); break; case RATIONAL: new_type=rational_typet(); break; case REAL: new_type=real_typet(); break; case INTEGER: new_type=integer_typet(); break; case COMPLEX: return; // do nothing default: return; } if(new_type!=expr_type) { if(new_type.id()==ID_pointer && expr_type.id()==ID_array) { exprt index_expr(ID_index, expr_type.subtype()); index_expr.reserve_operands(2); index_expr.move_to_operands(expr); index_expr.copy_to_operands(gen_zero(index_type())); expr=exprt(ID_address_of, new_type); expr.move_to_operands(index_expr); } else do_typecast(expr, new_type); } }
void c_typecastt::do_typecast(exprt &expr, const typet &type) { // special case: array -> pointer is actually // something like address_of const typet &expr_type=ns.follow(expr.type()); if(expr_type.id()==ID_array) { index_exprt index; index.array()=expr; index.index()=gen_zero(index_type()); index.type()=expr_type.subtype(); expr=address_of_exprt(index); if(ns.follow(expr.type())!=ns.follow(type)) expr.make_typecast(type); return; } if(expr_type!=type) { // C booleans are special: we compile to ?0:1 if(type.get(ID_C_c_type)==ID_bool) { if(expr_type.id()==ID_bool) // bool -> _Bool { exprt result=if_exprt(expr, gen_one(type), gen_zero(type)); expr.swap(result); } else // * -> _Bool { equal_exprt equal_zero(expr, gen_zero(expr_type)); exprt result=if_exprt(equal_zero, gen_zero(type), gen_one(type)); expr.swap(result); } } else { expr.make_typecast(type); } } }
void goto_symext::process_array_expr_rec( exprt &expr, const typet &type) const { if(expr.id()==ID_if) { if_exprt &if_expr=to_if_expr(expr); process_array_expr_rec(if_expr.true_case(), type); process_array_expr_rec(if_expr.false_case(), type); } else if(expr.id()==ID_index) { // strip index index_exprt &index_expr=to_index_expr(expr); exprt tmp=index_expr.array(); expr.swap(tmp); } else if(expr.id()==ID_typecast) { // strip exprt tmp=to_typecast_expr(expr).op0(); expr.swap(tmp); process_array_expr_rec(expr, type); } else if(expr.id()==ID_address_of) { // strip exprt tmp=to_address_of_expr(expr).op0(); expr.swap(tmp); process_array_expr_rec(expr, type); } else if(expr.id()==ID_symbol && expr.get_bool(ID_C_SSA_symbol) && to_ssa_expr(expr).get_original_expr().id()==ID_index) { const ssa_exprt &ssa=to_ssa_expr(expr); const index_exprt &index_expr=to_index_expr(ssa.get_original_expr()); exprt tmp=index_expr.array(); expr.swap(tmp); } else Forall_operands(it, expr) process_array_expr_rec(*it, it->type()); if(!base_type_eq(expr.type(), type, ns)) { byte_extract_exprt be(byte_extract_id()); be.type()=type; be.op()=expr; be.offset()=gen_zero(index_type()); expr.swap(be); } }
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::undefined_shift_check( const shift_exprt &expr, const guardt &guard) { if(!enable_undefined_shift_check) return; // Undefined for all types and shifts if distance exceeds width, // and also undefined for negative distances. const typet &distance_type= ns.follow(expr.distance().type()); if(distance_type.id()==ID_signedbv) { binary_relation_exprt inequality( expr.distance(), ID_ge, gen_zero(distance_type)); add_guarded_claim( inequality, "shift distance is negative", "undefined-shift", expr.find_source_location(), expr, guard); } const typet &op_type= ns.follow(expr.op().type()); if(op_type.id()==ID_unsignedbv || op_type.id()==ID_signedbv) { exprt width_expr= from_integer(to_bitvector_type(op_type).get_width(), distance_type); if(width_expr.is_nil()) throw "no number for width for operator "+expr.id_string(); binary_relation_exprt inequality( expr.distance(), ID_lt, width_expr); add_guarded_claim( inequality, "shift distance too large", "undefined-shift", expr.find_source_location(), expr, guard); } }
exprt gen_one(const typet &type) { const irep_idt type_id=type.id(); exprt result=constant_exprt(type); if(type_id==ID_bool || type_id==ID_rational || type_id==ID_real || type_id==ID_integer || type_id==ID_natural) { result.set(ID_value, ID_1); } else if(type_id==ID_unsignedbv || type_id==ID_signedbv || type_id==ID_c_enum) { std::string value; unsigned width=to_bitvector_type(type).get_width(); for(unsigned i=0; i<width-1; i++) value+='0'; value+='1'; result.set(ID_value, value); } else if(type_id==ID_fixedbv) { fixedbvt fixedbv; fixedbv.spec=to_fixedbv_type(type); fixedbv.from_integer(1); result=fixedbv.to_expr(); } else if(type_id==ID_floatbv) { ieee_floatt ieee_float; ieee_float.spec=to_floatbv_type(type); ieee_float.from_integer(1); result=ieee_float.to_expr(); } else if(type_id==ID_complex) { result=exprt(ID_complex, type); result.operands().resize(2); result.op0()=gen_one(type.subtype()); result.op1()=gen_zero(type.subtype()); } else result.make_nil(); return result; }
exprt gen_zero(const typet &type) { exprt result; const irep_idt type_id=type.id(); result=constant_exprt(type); if(type_id==ID_rational || type_id==ID_real || type_id==ID_integer || type_id==ID_natural || type_id==ID_complex || type_id==ID_c_enum) { result.set(ID_value, ID_0); } else if(type_id==ID_unsignedbv || type_id==ID_signedbv || type_id==ID_verilogbv || type_id==ID_floatbv || type_id==ID_fixedbv) { std::string value; unsigned width=to_bitvector_type(type).get_width(); for(unsigned i=0; i<width; i++) value+='0'; result.set(ID_value, value); } else if(type_id==ID_complex) { result=exprt(ID_complex, type); exprt sub_zero=gen_zero(type.subtype()); result.operands().resize(2, sub_zero); } else if(type_id==ID_bool) { result.make_false(); } else if(type_id==ID_pointer) { result.set(ID_value, ID_NULL); } else result.make_nil(); return result; }
void java_bytecode_convertt::convert( symbolt &class_symbol, const fieldt &f) { class_typet &class_type=to_class_type(class_symbol.type); typet member_type=java_type_from_string(f.signature); class_type.components().push_back(class_typet::componentt()); class_typet::componentt &component=class_type.components().back(); component.set_name(f.name); component.set_base_name(f.name); component.set_pretty_name(f.name); component.type()=member_type; if(f.is_private) component.set_access(ID_private); else if(f.is_protected) component.set_access(ID_protected); else if(f.is_public) component.set_access(ID_public); // is this a static field? if(f.is_static) { // create the symbol symbolt new_symbol; new_symbol.is_static_lifetime=true; new_symbol.is_lvalue=true; new_symbol.is_state_var=true; new_symbol.name=id2string(class_symbol.name)+"."+id2string(f.name); new_symbol.base_name=f.name; new_symbol.type=member_type; new_symbol.pretty_name=id2string(class_symbol.pretty_name)+"."+id2string(f.name); new_symbol.mode=ID_java; new_symbol.is_type=false; new_symbol.value=gen_zero(member_type); if(symbol_table.add(new_symbol)) { error() << "failed to add static field symbol" << eom; throw 0; } } }
exprt dereferencet::operator()(const exprt &pointer) { if(pointer.type().id()!=ID_pointer) throw "dereference expected pointer type, but got "+ pointer.type().pretty(); // type of the object const typet &type=pointer.type().subtype(); #ifdef DEBUG std::cout << "DEREF: " << from_expr(ns, "", pointer) << std::endl; #endif return dereference_rec( pointer, gen_zero(index_type()), // offset type); }
void c_typecastt::do_typecast(exprt &expr, const typet &dest_type) { // special case: array -> pointer is actually // something like address_of const typet &src_type=ns.follow(expr.type()); if(src_type.id()==ID_array) { index_exprt index; index.array()=expr; index.index()=gen_zero(index_type()); index.type()=src_type.subtype(); expr=address_of_exprt(index); if(ns.follow(expr.type())!=ns.follow(dest_type)) expr.make_typecast(dest_type); return; } if(src_type!=dest_type) { // C booleans are special; we produce the // explicit comparision with zero. // Note that this requires ieee_float_notequal // in case of floating-point numbers. if(dest_type.get(ID_C_c_type)==ID_bool) { expr=is_not_zero(expr, ns); expr.make_typecast(dest_type); } else if(dest_type.id()==ID_bool) { expr=is_not_zero(expr, ns); } else { expr.make_typecast(dest_type); } } }
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); }
bool simplify_exprt::simplify_address_of(exprt &expr) { if(expr.operands().size()!=1) return true; if(ns.follow(expr.type()).id()!=ID_pointer) return true; exprt &object=expr.op0(); bool result=simplify_address_of_arg(object); if(object.id()==ID_index) { index_exprt &index_expr=to_index_expr(object); if(!index_expr.index().is_zero()) { // we normalize &a[i] to (&a[0])+i exprt offset; offset.swap(index_expr.op1()); index_expr.op1()=gen_zero(offset.type()); exprt addition(ID_plus, expr.type()); addition.move_to_operands(expr, offset); expr.swap(addition); return false; } } else if(object.id()==ID_dereference) { // simplify &*p to p assert(object.operands().size()==1); exprt tmp=object.op0(); expr=tmp; return false; } return result; }
exprt convert_float_literal(const std::string &src) { mp_integer significand; mp_integer exponent; bool is_float, is_long, is_imaginary; bool is_decimal, is_float80, is_float128; // GCC extensions unsigned base; parse_float(src, significand, exponent, base, is_float, is_long, is_imaginary, is_decimal, is_float80, is_float128); exprt result=exprt(ID_constant); result.set(ID_C_cformat, src); // In ANSI-C, float literals are double by default, // unless marked with 'f'. // All of these can be complex as well. // This can be overriden with // config.ansi_c.single_precision_constant. if(is_float) result.type()=float_type(); else if(is_long) result.type()=long_double_type(); else if(is_float80) { result.type()=ieee_float_spect(64, 15).to_type(); result.type().set(ID_C_c_type, ID_long_double); } else if(is_float128) { result.type()=ieee_float_spect::quadruple_precision().to_type(); result.type().set(ID_C_c_type, ID_gcc_float128); } else { // default if(config.ansi_c.single_precision_constant) result.type()=float_type(); // default else result.type()=double_type(); // default } if(is_decimal) { // TODO - should set ID_gcc_decimal32/ID_gcc_decimal64/ID_gcc_decimal128, // but these aren't handled anywhere } if(config.ansi_c.use_fixed_for_float) { unsigned width=result.type().get_int(ID_width); unsigned fraction_bits; const irep_idt integer_bits=result.type().get(ID_integer_bits); assert(width!=0); if(integer_bits==irep_idt()) fraction_bits=width/2; // default else fraction_bits=width-safe_string2int(id2string(integer_bits)); mp_integer factor=mp_integer(1)<<fraction_bits; mp_integer value=significand*factor; if(value!=0) { if(exponent<0) value/=power(base, -exponent); else { value*=power(base, exponent); if(value>=power(2, width-1)) { // saturate: use "biggest value" value=power(2, width-1)-1; } else if(value<=-power(2, width-1)-1) { // saturate: use "smallest value" value=-power(2, width-1); } } } result.set(ID_value, integer2binary(value, width)); } else { ieee_floatt a; a.spec=to_floatbv_type(result.type()); if(base==10) a.from_base10(significand, exponent); else if(base==2) // hex a.build(significand, exponent); else assert(false); result.set(ID_value, integer2binary(a.pack(), a.spec.width())); } if(is_imaginary) { complex_typet complex_type; complex_type.subtype()=result.type(); exprt complex_expr(ID_complex, complex_type); complex_expr.operands().resize(2); complex_expr.op0()=gen_zero(result.type()); complex_expr.op1()=result; return complex_expr; } return result; }
bool c_typecheck_baset::zero_initializer(exprt &value, const typet &type) const { const std::string &type_id = type.id_string(); if(type_id == "bool") { value.make_false(); return false; } if( type_id == "unsignedbv" || type_id == "signedbv" || type_id == "floatbv" || type_id == "fixedbv" || type_id == "pointer") { value = gen_zero(type); return false; } else if(type_id == "code") return false; else if(type_id == "c_enum" || type_id == "incomplete_c_enum") { value = exprt("constant", type); value.value(i2string(0)); return false; } else if(type_id == "array") { const array_typet &array_type = to_array_type(type); exprt tmpval; if(zero_initializer(tmpval, array_type.subtype())) return true; const exprt &size_expr = array_type.size(); if(size_expr.id() == "infinity") { } else { mp_integer size; if(to_integer(size_expr, size)) return true; // Permit GCC zero sized arrays; disallow negative sized arrays. // Cringe slightly when doing it though. if(size < 0) return true; } value = exprt("array_of", type); value.move_to_operands(tmpval); return false; } else if(type_id == "struct") { const irept::subt &components = type.components().get_sub(); value = exprt("struct", type); forall_irep(it, components) { exprt tmp; if(zero_initializer(tmp, (const typet &)it->type())) return true; value.move_to_operands(tmp); } return false; }
exprt convert_integer_literal(const std::string &src) { bool is_unsigned=false, is_imaginary=false; unsigned long_cnt=0; unsigned width_suffix=0; unsigned base=10; for(unsigned i=0; i<src.size(); i++) { register char ch=src[i]; if(ch=='u' || ch=='U') is_unsigned=true; else if(ch=='l' || ch=='L') long_cnt++; else if(ch=='i' || ch=='I') { // This can be "1i128" in MS mode, // and "10i" (imaginary) for GCC. // If it's followed by a number, we do MS mode. if((i+1)<src.size() && isdigit(src[i+1])) width_suffix=atoi(src.c_str()+i+1); else is_imaginary=true; } else if(ch=='j' || ch=='J') is_imaginary=true; } mp_integer value; if(src.size()>=2 && src[0]=='0' && tolower(src[1])=='x') { // hex; strip "0x" base=16; std::string without_prefix(src, 2, std::string::npos); value=string2integer(without_prefix, 16); } else if(src.size()>=2 && src[0]=='0' && tolower(src[1])=='b') { // binary; strip "0x" // see http://gcc.gnu.org/onlinedocs/gcc/Binary-constants.html base=2; std::string without_prefix(src, 2, std::string::npos); value=string2integer(without_prefix, 2); } else if(src.size()>=2 && src[0]=='0') { // octal base=8; value=string2integer(src, 8); } else { // The default is base 10. value=string2integer(src, 10); } if(width_suffix!=0) { // this is a Microsoft extension irep_idt c_type; if(width_suffix<=config.ansi_c.int_width) c_type=is_unsigned?ID_unsigned_int:ID_signed_int; else if(width_suffix<=config.ansi_c.long_int_width) c_type=is_unsigned?ID_unsigned_long_int:ID_signed_long_int; else c_type=is_unsigned?ID_unsigned_long_long_int:ID_signed_long_long_int; typet type=typet(is_unsigned?ID_unsignedbv:ID_signedbv); type.set(ID_width, width_suffix); type.set(ID_C_c_type, c_type); exprt result=from_integer(value, type); result.set(ID_C_cformat, src); return result; } mp_integer value_abs=value; if(value<0) value_abs.negate(); bool is_hex_or_oct_or_bin=(base==8) || (base==16) || (base==2); #define FITS(width, signed) \ ((signed?!is_unsigned:(is_unsigned || is_hex_or_oct_or_bin)) && \ (power(2, signed?width-1:width)>value_abs)) unsigned width; bool is_signed=false; irep_idt c_type; if(FITS(config.ansi_c.int_width, true) && long_cnt==0) // int { width=config.ansi_c.int_width; is_signed=true; c_type=ID_signed_int; } else if(FITS(config.ansi_c.int_width, false) && long_cnt==0) // unsigned int { width=config.ansi_c.int_width; is_signed=false; c_type=ID_unsigned_int; } else if(FITS(config.ansi_c.long_int_width, true) && long_cnt!=2) // long int { width=config.ansi_c.long_int_width; is_signed=true; c_type=ID_signed_long_int; } else if(FITS(config.ansi_c.long_int_width, false) && long_cnt!=2) // unsigned long int { width=config.ansi_c.long_int_width; is_signed=false; c_type=ID_unsigned_long_int; } else if(FITS(config.ansi_c.long_long_int_width, true)) // long long int { width=config.ansi_c.long_long_int_width; is_signed=true; c_type=ID_signed_long_long_int; } else if(FITS(config.ansi_c.long_long_int_width, false)) // unsigned long long int { width=config.ansi_c.long_long_int_width; is_signed=false; c_type=ID_unsigned_long_long_int; } else { // Way too large. Should consider issuing a warning. width=config.ansi_c.long_long_int_width; if(is_unsigned) { is_signed=false; c_type=ID_unsigned_long_long_int; } else c_type=ID_signed_long_long_int; } typet type=typet(is_signed?ID_signedbv:ID_unsignedbv); type.set(ID_width, width); type.set(ID_C_c_type, c_type); exprt result; if(is_imaginary) { complex_typet complex_type; complex_type.subtype()=type; result=exprt(ID_complex, complex_type); result.operands().resize(2); result.op0()=gen_zero(type); result.op1()=from_integer(value, type); } else { result=from_integer(value, type); result.set(ID_C_cformat, src); } return result; }
void cpp_typecheckt::do_virtual_table(const symbolt &symbol) { assert(symbol.type.id()==ID_struct); // builds virtual-table value maps: (class x virtual_name x value) std::map<irep_idt, std::map<irep_idt,exprt> > vt_value_maps; const struct_typet &struct_type = to_struct_type(symbol.type); for(unsigned i = 0; i < struct_type.components().size(); i++) { const struct_typet::componentt& compo = struct_type.components()[i]; if(!compo.get_bool("is_virtual")) continue; const code_typet& code_type = to_code_type(compo.type()); assert(code_type.arguments().size() > 0); const pointer_typet& pointer_type = static_cast<const pointer_typet&>(code_type.arguments()[0].type()); irep_idt class_id = pointer_type.subtype().get("identifier"); std::map<irep_idt,exprt>& value_map = vt_value_maps[class_id]; exprt e = symbol_exprt(compo.get_name(),code_type); if(compo.get_bool("is_pure_virtual")) { pointer_typet pointer_type(code_type); e = gen_zero(pointer_type); assert(e.is_not_nil()); value_map[compo.get("virtual_name")] = e; } else { address_of_exprt address(e); value_map[compo.get("virtual_name")] = address; } } // create virtual-table symbol variables for(std::map<irep_idt, std::map<irep_idt,exprt> >::const_iterator cit = vt_value_maps.begin(); cit != vt_value_maps.end(); cit++) { const std::map<irep_idt,exprt>& value_map = cit->second; const symbolt& late_cast_symb = namespacet(symbol_table).lookup(cit->first); const symbolt& vt_symb_type = namespacet(symbol_table).lookup("virtual_table::"+id2string(late_cast_symb.name)); symbolt vt_symb_var; vt_symb_var.name= id2string(vt_symb_type.name) + "@"+ id2string(symbol.name); vt_symb_var.base_name= id2string(vt_symb_type.base_name) + "@" + id2string(symbol.base_name); vt_symb_var.mode=ID_cpp; vt_symb_var.module=module; vt_symb_var.location=vt_symb_type.location; vt_symb_var.type = symbol_typet(vt_symb_type.name); vt_symb_var.is_lvalue = true; vt_symb_var.is_static_lifetime = true; // do the values const struct_typet &vt_type = to_struct_type(vt_symb_type.type); exprt values(ID_struct, symbol_typet(vt_symb_type.name)); for(unsigned i=0; i < vt_type.components().size(); i++) { const struct_typet::componentt& compo = vt_type.components()[i]; std::map<irep_idt,exprt>::const_iterator cit2 = value_map.find( compo.get("base_name")); assert(cit2 != value_map.end()); const exprt& value = cit2->second; assert(value.type() == compo.type()); values.operands().push_back(value); } vt_symb_var.value = values; bool failed = symbol_table.move(vt_symb_var); assert(!failed); } }
void goto_checkt::pointer_validity_check( const dereference_exprt &expr, const guardt &guard) { if(!enable_pointer_check) return; const exprt &pointer=expr.op0(); const typet &pointer_type=to_pointer_type(ns.follow(pointer.type())); assert(base_type_eq(pointer_type.subtype(), expr.type(), ns)); local_bitvector_analysist::flagst flags= local_bitvector_analysis->get(t, pointer); const typet &dereference_type=pointer_type.subtype(); // For Java, we only need to check for null if(mode==ID_java) { if(flags.is_unknown() || flags.is_null()) { notequal_exprt not_eq_null(pointer, gen_zero(pointer.type())); add_guarded_claim( not_eq_null, "reference is null", "pointer dereference", expr.find_source_location(), expr, guard); } } else { if(flags.is_unknown() || flags.is_null()) { add_guarded_claim( not_exprt(null_pointer(pointer)), "dereference failure: pointer NULL", "pointer dereference", expr.find_source_location(), expr, guard); } if(flags.is_unknown()) add_guarded_claim( not_exprt(invalid_pointer(pointer)), "dereference failure: pointer invalid", "pointer dereference", expr.find_source_location(), expr, guard); if(flags.is_uninitialized()) add_guarded_claim( not_exprt(invalid_pointer(pointer)), "dereference failure: pointer uninitialized", "pointer dereference", expr.find_source_location(), expr, guard); if(mode != ID_java) { if(flags.is_unknown() || flags.is_dynamic_heap()) add_guarded_claim( not_exprt(deallocated(pointer, ns)), "dereference failure: deallocated dynamic object", "pointer dereference", expr.find_source_location(), expr, guard); if(flags.is_unknown() || flags.is_dynamic_local()) add_guarded_claim( not_exprt(dead_object(pointer, ns)), "dereference failure: dead object", "pointer dereference", expr.find_source_location(), expr, guard); } if(enable_bounds_check) { if(flags.is_unknown() || flags.is_dynamic_heap()) { exprt dynamic_bounds= or_exprt(dynamic_object_lower_bound(pointer), dynamic_object_upper_bound(pointer, dereference_type, ns)); add_guarded_claim( implies_exprt(malloc_object(pointer, ns), not_exprt(dynamic_bounds)), "dereference failure: dynamic object bounds", "pointer dereference", expr.find_source_location(), expr, guard); } } if(enable_bounds_check) { if(flags.is_unknown() || flags.is_dynamic_local() || flags.is_static_lifetime()) { exprt object_bounds= or_exprt(object_lower_bound(pointer), object_upper_bound(pointer, dereference_type, ns)); add_guarded_claim( or_exprt(dynamic_object(pointer), not_exprt(object_bounds)), "dereference failure: object bounds", "pointer dereference", expr.find_source_location(), expr, guard); } } } }
static inline __m128 gen_ones(void) { __m128 x = gen_zero(); __m128 ones = _mm_cmpeq_ps(x, x); return ones; }
void goto_convertt::do_java_new_array( const exprt &lhs, const side_effect_exprt &rhs, goto_programt &dest) { if(lhs.is_nil()) throw "do_java_new_array without lhs is yet to be implemented"; source_locationt location=rhs.source_location(); assert(rhs.operands().size()>=1); // one per dimension if(rhs.type().id()!=ID_pointer) throw "do_java_new_array returns pointer"; typet object_type=rhs.type().subtype(); // build size expression exprt object_size=size_of_expr(object_type, ns); if(object_size.is_nil()) throw "do_java_new_array got nil object_size"; // we produce a malloc side-effect, which stays side_effect_exprt malloc_expr(ID_malloc); malloc_expr.copy_to_operands(object_size); malloc_expr.type()=pointer_typet(object_type); goto_programt::targett t_n=dest.add_instruction(ASSIGN); t_n->code=code_assignt(lhs, malloc_expr); t_n->source_location=location; // multi-dimensional? assert(ns.follow(object_type).id()==ID_struct); const struct_typet &struct_type=to_struct_type(ns.follow(object_type)); assert(struct_type.components().size()==3); // if it's an array, we need to set the length field dereference_exprt deref(lhs, object_type); member_exprt length(deref, struct_type.components()[1].get_name(), struct_type.components()[1].type()); goto_programt::targett t_s=dest.add_instruction(ASSIGN); t_s->code=code_assignt(length, rhs.op0()); t_s->source_location=location; // we also need to allocate space for the data member_exprt data(deref, struct_type.components()[2].get_name(), struct_type.components()[2].type()); side_effect_exprt data_cpp_new_expr(ID_cpp_new_array, data.type()); data_cpp_new_expr.set(ID_size, rhs.op0()); goto_programt::targett t_p=dest.add_instruction(ASSIGN); t_p->code=code_assignt(data, data_cpp_new_expr); t_p->source_location=location; // zero-initialize the data exprt zero_element=gen_zero(data.type().subtype()); codet array_set(ID_array_set); array_set.copy_to_operands(data, zero_element); goto_programt::targett t_d=dest.add_instruction(OTHER); t_d->code=array_set; t_d->source_location=location; if(rhs.operands().size()>=2) { // produce // for(int i=0; i<size; i++) tmp[i]=java_new(dim-1); // This will be converted recursively. goto_programt tmp; symbol_exprt tmp_i= new_tmp_symbol(index_type(), "index", tmp, location).symbol_expr(); code_fort for_loop; side_effect_exprt sub_java_new=rhs; sub_java_new.operands().erase(sub_java_new.operands().begin()); side_effect_exprt inc(ID_assign); inc.operands().resize(2); inc.op0()=tmp_i; inc.op1()=plus_exprt(tmp_i, gen_one(tmp_i.type())); dereference_exprt deref_expr(plus_exprt(data, tmp_i), data.type().subtype()); for_loop.init()=code_assignt(tmp_i, gen_zero(tmp_i.type())); for_loop.cond()=binary_relation_exprt(tmp_i, ID_lt, rhs.op0()); for_loop.iter()=inc; for_loop.body()=code_skipt(); for_loop.body()=code_assignt(deref_expr, sub_java_new); convert(for_loop, tmp); dest.destructive_append(tmp); } }
void dplib_convt::convert_dplib_expr(const exprt &expr) { if(expr.id()==ID_symbol) { convert_identifier(expr.get_string(ID_identifier)); } else if(expr.id()==ID_nondet_symbol) { convert_identifier("nondet$"+expr.get_string(ID_identifier)); } else if(expr.id()==ID_typecast) { assert(expr.operands().size()==1); const exprt &op=expr.op0(); if(expr.type().id()==ID_bool) { if(op.type().id()==ID_signedbv || op.type().id()==ID_unsignedbv || op.type().id()==ID_pointer) { convert_dplib_expr(op); dplib_prop.out << "/="; convert_dplib_expr(gen_zero(op.type())); } else { throw "TODO typecast1 "+op.type().id_string()+" -> bool"; } } else if(expr.type().id()==ID_signedbv || expr.type().id()==ID_unsignedbv) { unsigned to_width=unsafe_string2unsigned(id2string(expr.type().get(ID_width))); if(op.type().id()==ID_signedbv) { unsigned from_width=unsafe_string2unsigned(id2string(op.type().get(ID_width))); if(from_width==to_width) convert_dplib_expr(op); else if(from_width<to_width) { dplib_prop.out << "SX("; convert_dplib_expr(op); dplib_prop.out << ", " << to_width << ")"; } else { dplib_prop.out << "("; convert_dplib_expr(op); dplib_prop.out << ")[" << (to_width-1) << ":0]"; } } else if(op.type().id()==ID_unsignedbv) { unsigned from_width=unsafe_string2unsigned(id2string(op.type().get(ID_width))); if(from_width==to_width) convert_dplib_expr(op); else if(from_width<to_width) { dplib_prop.out << "(0bin"; for(unsigned i=from_width; i<to_width; i++) dplib_prop.out << "0"; dplib_prop.out << " @ "; dplib_prop.out << "("; convert_dplib_expr(op); dplib_prop.out << "))"; } else { dplib_prop.out << "("; convert_dplib_expr(op); dplib_prop.out << ")[" << (to_width-1) << ":0]"; } } else if(op.type().id()==ID_bool) { if(to_width>1) { dplib_prop.out << "(0bin"; for(unsigned i=1; i<to_width; i++) dplib_prop.out << "0"; dplib_prop.out << " @ "; dplib_prop.out << "IF "; convert_dplib_expr(op); dplib_prop.out << " THEN 0bin1 ELSE 0bin0 ENDIF)"; } else { dplib_prop.out << "IF "; convert_dplib_expr(op); dplib_prop.out << " THEN 0bin1 ELSE 0bin0 ENDIF"; } } else { throw "TODO typecast2 "+op.type().id_string()+ " -> "+expr.type().id_string(); } } else if(expr.type().id()==ID_pointer) { if(op.type().id()==ID_pointer) { convert_dplib_expr(op); } else throw "TODO typecast3 "+op.type().id_string()+" -> pointer"; } else throw "TODO typecast4 ? -> "+expr.type().id_string(); } else if(expr.id()==ID_struct) { dplib_prop.out << "(# "; const struct_typet &struct_type=to_struct_type(expr.type()); const struct_typet::componentst &components= struct_type.components(); assert(components.size()==expr.operands().size()); unsigned i=0; for(struct_typet::componentst::const_iterator it=components.begin(); it!=components.end(); it++, i++) { if(i!=0) dplib_prop.out << ", "; dplib_prop.out << it->get(ID_name); dplib_prop.out << ":="; convert_dplib_expr(expr.operands()[i]); } dplib_prop.out << " #)"; } else if(expr.id()==ID_constant) { if(expr.type().id()==ID_unsignedbv || expr.type().id()==ID_signedbv || expr.type().id()==ID_bv) { dplib_prop.out << "0bin" << expr.get(ID_value); } else if(expr.type().id()==ID_pointer) { const irep_idt &value=expr.get(ID_value); if(value=="NULL") { dplib_prop.out << "(# object:=" << pointer_logic.get_null_object() << ", offset:=" << bin_zero(config.ansi_c.pointer_width) << " #)"; } else throw "unknown pointer constant: "+id2string(value); } else if(expr.type().id()==ID_bool) { if(expr.is_true()) dplib_prop.out << "TRUE"; else if(expr.is_false()) dplib_prop.out << "FALSE"; else throw "unknown boolean constant"; } else if(expr.type().id()==ID_array) { dplib_prop.out << "ARRAY (i: " << array_index_type() << "):"; assert(!expr.operands().empty()); unsigned i=0; forall_operands(it, expr) { if(i==0) dplib_prop.out << "\n IF "; else dplib_prop.out << "\n ELSIF "; dplib_prop.out << "i=" << array_index(i) << " THEN "; convert_array_value(*it); i++; } dplib_prop.out << "\n ELSE "; convert_dplib_expr(expr.op0()); dplib_prop.out << "\n ENDIF"; } else if(expr.type().id()==ID_integer ||
void goto_checkt::goto_check(goto_functiont &goto_function) { { const symbolt *init_symbol; if(!ns.lookup(CPROVER_PREFIX "initialize", init_symbol)) mode=init_symbol->mode; } assertions.clear(); local_bitvector_analysist local_bitvector_analysis_obj(goto_function); local_bitvector_analysis=&local_bitvector_analysis_obj; goto_programt &goto_program=goto_function.body; Forall_goto_program_instructions(it, goto_program) { t=it; goto_programt::instructiont &i=*it; new_code.clear(); // we clear all recorded assertions if // 1) we want to generate all assertions or // 2) the instruction is a branch target if(retain_trivial || i.is_target()) assertions.clear(); check(i.guard); // magic ERROR label? for(optionst::value_listt::const_iterator l_it=error_labels.begin(); l_it!=error_labels.end(); l_it++) { if(std::find(i.labels.begin(), i.labels.end(), *l_it)!=i.labels.end()) { goto_program_instruction_typet type= enable_assert_to_assume?ASSUME:ASSERT; goto_programt::targett t=new_code.add_instruction(type); t->guard=false_exprt(); t->source_location=i.source_location; t->source_location.set_property_class("error label"); t->source_location.set_comment("error label "+*l_it); t->source_location.set("user-provided", true); } } if(i.is_other()) { const irep_idt &statement=i.code.get(ID_statement); if(statement==ID_expression) { check(i.code); } else if(statement==ID_printf) { forall_operands(it, i.code) check(*it); } } else if(i.is_assign()) { const code_assignt &code_assign=to_code_assign(i.code); check(code_assign.lhs()); check(code_assign.rhs()); // the LHS might invalidate any assertion invalidate(code_assign.lhs()); } else if(i.is_function_call()) { const code_function_callt &code_function_call= to_code_function_call(i.code); // for Java, need to check whether 'this' is null // on non-static method invocations if(mode==ID_java && enable_pointer_check && !code_function_call.arguments().empty() && code_function_call.function().type().id()==ID_code && to_code_type(code_function_call.function().type()).has_this()) { exprt pointer=code_function_call.arguments()[0]; local_bitvector_analysist::flagst flags= local_bitvector_analysis->get(t, pointer); if(flags.is_unknown() || flags.is_null()) { notequal_exprt not_eq_null(pointer, gen_zero(pointer.type())); add_guarded_claim( not_eq_null, "this is null on method invokation", "pointer dereference", i.source_location, pointer, guardt()); } } forall_operands(it, code_function_call) check(*it); // the call might invalidate any assertion assertions.clear(); } else if(i.is_return()) { if(i.code.operands().size()==1) { check(i.code.op0()); // the return value invalidate any assertion invalidate(i.code.op0()); } } else if(i.is_throw()) { if(i.code.get_statement()==ID_expression && i.code.operands().size()==1 && i.code.op0().operands().size()==1) { // must not throw NULL exprt pointer=i.code.op0().op0(); if(pointer.type().subtype().get(ID_identifier)!="java::java.lang.AssertionError") { notequal_exprt not_eq_null(pointer, gen_zero(pointer.type())); add_guarded_claim( not_eq_null, "throwing null", "pointer dereference", i.source_location, pointer, guardt()); } } // this has no successor assertions.clear(); } else if(i.is_assert()) { if(i.source_location.get_bool("user-provided") && i.source_location.get_property_class()!="error label" && !enable_assertions) i.type=SKIP; } else if(i.is_assume()) { if(!enable_assumptions) i.type=SKIP; } else if(i.is_dead()) { if(enable_pointer_check) { assert(i.code.operands().size()==1); const symbol_exprt &variable=to_symbol_expr(i.code.op0()); // is it dirty? if(local_bitvector_analysis->dirty(variable)) { // need to mark the dead variable as dead goto_programt::targett t=new_code.add_instruction(ASSIGN); exprt address_of_expr=address_of_exprt(variable); exprt lhs=ns.lookup(CPROVER_PREFIX "dead_object").symbol_expr(); if(!base_type_eq(lhs.type(), address_of_expr.type(), ns)) address_of_expr.make_typecast(lhs.type()); exprt rhs=if_exprt( side_effect_expr_nondett(bool_typet()), address_of_expr, lhs, lhs.type()); t->source_location=i.source_location; t->code=code_assignt(lhs, rhs); t->code.add_source_location()=i.source_location; } } } else if(i.is_end_function()) { if(i.function==goto_functionst::entry_point() && enable_memory_leak_check) { const symbolt &leak=ns.lookup(CPROVER_PREFIX "memory_leak"); const symbol_exprt leak_expr=leak.symbol_expr(); // add self-assignment to get helpful counterexample output goto_programt::targett t=new_code.add_instruction(); t->make_assignment(); t->code=code_assignt(leak_expr, leak_expr); source_locationt source_location; source_location.set_function(i.function); equal_exprt eq(leak_expr, gen_zero(ns.follow(leak.type))); add_guarded_claim( eq, "dynamically allocated memory never freed", "memory-leak", source_location, eq, guardt()); } } for(goto_programt::instructionst::iterator i_it=new_code.instructions.begin(); i_it!=new_code.instructions.end(); i_it++) { if(i_it->source_location.is_nil()) { i_it->source_location.id(irep_idt()); if(it->source_location.get_file()!=irep_idt()) i_it->source_location.set_file(it->source_location.get_file()); if(it->source_location.get_line()!=irep_idt()) i_it->source_location.set_line(it->source_location.get_line()); if(it->source_location.get_function()!=irep_idt()) i_it->source_location.set_function(it->source_location.get_function()); if(it->source_location.get_column()!=irep_idt()) i_it->source_location.set_column(it->source_location.get_column()); } if(i_it->function==irep_idt()) i_it->function=it->function; } // insert new instructions -- make sure targets are not moved while(!new_code.instructions.empty()) { goto_program.insert_before_swap(it, new_code.instructions.front()); new_code.instructions.pop_front(); it++; } }
void string_instrumentationt::invalidate_buffer( goto_programt &dest, goto_programt::const_targett target, const exprt &buffer, const typet &buf_type, const mp_integer &limit) { irep_idt cntr_id="string_instrumentation::$counter"; if(context.symbols.find(cntr_id)==context.symbols.end()) { symbolt new_symbol; new_symbol.base_name="$counter"; new_symbol.pretty_name=new_symbol.base_name; new_symbol.name=cntr_id; new_symbol.mode="C"; new_symbol.type=uint_type(); new_symbol.is_statevar=true; new_symbol.lvalue=true; new_symbol.static_lifetime=true; context.move(new_symbol); } const symbolt &cntr_sym=ns.lookup(cntr_id); // create a loop that runs over the buffer // and invalidates every element goto_programt::targett init=dest.add_instruction(ASSIGN); init->location=target->location; init->code=code_assignt(symbol_expr(cntr_sym), gen_zero(cntr_sym.type)); goto_programt::targett check=dest.add_instruction(); check->location=target->location; goto_programt::targett invalidate=dest.add_instruction(ASSIGN); invalidate->location=target->location; goto_programt::targett increment=dest.add_instruction(ASSIGN); increment->location=target->location; exprt plus("+", uint_type()); plus.copy_to_operands(symbol_expr(cntr_sym)); plus.copy_to_operands(gen_one(uint_type())); increment->code=code_assignt(symbol_expr(cntr_sym), plus); goto_programt::targett back=dest.add_instruction(); back->location=target->location; back->make_goto(check); back->guard=true_exprt(); goto_programt::targett exit=dest.add_instruction(); exit->location=target->location; exit->make_skip(); exprt cnt_bs, bufp; if(buf_type.id()=="pointer") bufp = buffer; else { index_exprt index; index.array()=buffer; index.index()=gen_zero(uint_type()); index.type()=buf_type.subtype(); bufp = address_of_exprt(index); } exprt deref("dereference", buf_type.subtype()); exprt b_plus_i("+", bufp.type()); b_plus_i.copy_to_operands(bufp); b_plus_i.copy_to_operands(symbol_expr(cntr_sym)); deref.copy_to_operands(b_plus_i); check->make_goto(exit); if(limit==0) check->guard= binary_relation_exprt(symbol_expr(cntr_sym), ">=", buffer_size(bufp)); else check->guard= binary_relation_exprt(symbol_expr(cntr_sym), ">", from_integer(limit, uint_type())); exprt nondet=side_effect_expr_nondett(buf_type.subtype()); invalidate->code=code_assignt(deref, nondet); }
void goto_checkt::bounds_check( const index_exprt &expr, const guardt &guard) { if(!enable_bounds_check) return; if(expr.find("bounds_check").is_not_nil() && !expr.get_bool("bounds_check")) return; typet array_type=ns.follow(expr.array().type()); if(array_type.id()==ID_pointer) return; // done by the pointer code else if(array_type.id()==ID_incomplete_array) throw "index got incomplete array"; else if(array_type.id()!=ID_array && array_type.id()!=ID_vector) throw "bounds check expected array or vector type, got " +array_type.id_string(); std::string name=array_name(expr.array()); const exprt &index=expr.index(); object_descriptor_exprt ode; ode.build(expr, ns); if(index.type().id()!=ID_unsignedbv) { // we undo typecasts to signedbv if(index.id()==ID_typecast && index.operands().size()==1 && index.op0().type().id()==ID_unsignedbv) { // ok } else { mp_integer i; if(!to_integer(index, i) && i>=0) { // ok } else { exprt effective_offset=ode.offset(); if(ode.root_object().id()==ID_dereference) { exprt p_offset=pointer_offset( to_dereference_expr(ode.root_object()).pointer()); assert(p_offset.type()==effective_offset.type()); effective_offset=plus_exprt(p_offset, effective_offset); } exprt zero=gen_zero(ode.offset().type()); assert(zero.is_not_nil()); // the final offset must not be negative binary_relation_exprt inequality(effective_offset, ID_ge, zero); add_guarded_claim( inequality, name+" lower bound", "array bounds", expr.find_source_location(), expr, guard); } } } if(ode.root_object().id()==ID_dereference) { const exprt &pointer= to_dereference_expr(ode.root_object()).pointer(); if_exprt size( dynamic_object(pointer), typecast_exprt(dynamic_size(ns), object_size(pointer).type()), object_size(pointer)); plus_exprt effective_offset(ode.offset(), pointer_offset(pointer)); assert(effective_offset.op0().type()==effective_offset.op1().type()); assert(effective_offset.type()==size.type()); binary_relation_exprt inequality(effective_offset, ID_lt, size); or_exprt precond( and_exprt( dynamic_object(pointer), not_exprt(malloc_object(pointer, ns))), inequality); add_guarded_claim( precond, name+" upper bound", "array bounds", expr.find_source_location(), expr, guard); return; } const exprt &size=array_type.id()==ID_array ? to_array_type(array_type).size() : to_vector_type(array_type).size(); if(size.is_nil()) { // Linking didn't complete, we don't have a size. // Not clear what to do. } else if(size.id()==ID_infinity) { } else if(size.is_zero() && expr.array().id()==ID_member) { // a variable sized struct member } else { binary_relation_exprt inequality(index, ID_lt, size); // typecast size if(inequality.op1().type()!=inequality.op0().type()) inequality.op1().make_typecast(inequality.op0().type()); // typecast size if(inequality.op1().type()!=inequality.op0().type()) inequality.op1().make_typecast(inequality.op0().type()); add_guarded_claim( inequality, name+" upper bound", "array bounds", expr.find_source_location(), expr, guard); } }
void string_instrumentationt::do_format_string_read( goto_programt &dest, goto_programt::const_targett target, const code_function_callt::argumentst &arguments, unsigned format_string_inx, unsigned argument_start_inx, const std::string &function_name) { const exprt &format_arg = arguments[format_string_inx]; if(format_arg.id()=="address_of" && format_arg.op0().id()=="index" && format_arg.op0().op0().id()==ID_string_constant) { format_token_listt token_list; parse_format_string(format_arg.op0().op0(), token_list); unsigned args=0; for(format_token_listt::const_iterator it=token_list.begin(); it!=token_list.end(); it++) { if(it->type==format_tokent::STRING) { const exprt &arg = arguments[argument_start_inx+args]; const typet &arg_type = ns.follow(arg.type()); if(arg.id()!=ID_string_constant) // we don't need to check constants { goto_programt::targett assertion=dest.add_instruction(); assertion->location=target->location; assertion->location.set("property", "string"); std::string comment("zero-termination of string argument of "); comment += function_name; assertion->location.set("comment", comment); exprt temp(arg); if(arg_type.id()!="pointer") { index_exprt index; index.array()=temp; index.index()=gen_zero(uint_type()); index.type()=arg_type.subtype(); temp=address_of_exprt(index); } assertion->make_assertion(is_zero_string(temp)); } } if(it->type!=format_tokent::TEXT && it->type!=format_tokent::UNKNOWN) args++; if(find(it->flags.begin(), it->flags.end(), format_tokent::ASTERISK)!= it->flags.end()) args++; // just eat the additional argument } } else // non-const format string { goto_programt::targett format_ass=dest.add_instruction(); format_ass->make_assertion(is_zero_string(arguments[1])); format_ass->location=target->location; format_ass->location.set("property", "string"); std::string comment("zero-termination of format string of "); comment += function_name; format_ass->location.set("comment", comment); for(unsigned i=2; i<arguments.size(); i++) { const exprt &arg = arguments[i]; const typet &arg_type=ns.follow(arguments[i].type()); if(arguments[i].id()!=ID_string_constant && is_string_type(arg_type)) { goto_programt::targett assertion=dest.add_instruction(); assertion->location=target->location; assertion->location.set("property", "string"); std::string comment("zero-termination of string argument of "); comment += function_name; assertion->location.set("comment", comment); exprt temp(arg); if(arg_type.id()!="pointer") { index_exprt index; index.array()=temp; index.index()=gen_zero(uint_type()); index.type()=arg_type.subtype(); temp=address_of_exprt(index); } assertion->make_assertion(is_zero_string(temp)); } } } }
void string_instrumentationt::do_format_string_write( goto_programt &dest, goto_programt::const_targett target, const code_function_callt::argumentst &arguments, unsigned format_string_inx, unsigned argument_start_inx, const std::string &function_name) { const exprt &format_arg = arguments[format_string_inx]; if(format_arg.id()=="address_of" && format_arg.op0().id()=="index" && format_arg.op0().op0().id()==ID_string_constant) // constant format { format_token_listt token_list; parse_format_string(format_arg.op0().op0(), token_list); unsigned args=0; for(format_token_listt::const_iterator it=token_list.begin(); it!=token_list.end(); it++) { if(find(it->flags.begin(), it->flags.end(), format_tokent::ASTERISK)!= it->flags.end()) continue; // asterisk means `ignore this' switch(it->type) { case format_tokent::STRING: { const exprt &argument=arguments[argument_start_inx+args]; const typet &arg_type=ns.follow(argument.type()); goto_programt::targett assertion=dest.add_instruction(); assertion->location=target->location; assertion->location.set("property", "string"); std::string comment("format string buffer overflow in "); comment += function_name; assertion->location.set("comment", comment); if(it->field_width!=0) { exprt fwidth = from_integer(it->field_width, uint_type()); exprt fw_1("+", uint_type()); exprt one = gen_one(uint_type()); fw_1.move_to_operands(fwidth); fw_1.move_to_operands(one); // +1 for 0-char exprt fw_lt_bs; if(arg_type.id()=="pointer") fw_lt_bs=binary_relation_exprt(fw_1, "<=", buffer_size(argument)); else { index_exprt index; index.array()=argument; index.index()=gen_zero(uint_type()); address_of_exprt aof(index); fw_lt_bs=binary_relation_exprt(fw_1, "<=", buffer_size(aof)); } assertion->make_assertion(fw_lt_bs); } else { // this is a possible overflow. assertion->make_assertion(false_exprt()); } // now kill the contents invalidate_buffer(dest, target, argument, arg_type, it->field_width); args++; break; } case format_tokent::TEXT: case format_tokent::UNKNOWN: { // nothing break; } default: // everything else { const exprt &argument=arguments[argument_start_inx+args]; const typet &arg_type=ns.follow(argument.type()); goto_programt::targett assignment=dest.add_instruction(ASSIGN); assignment->location=target->location; exprt lhs("dereference", arg_type.subtype()); lhs.copy_to_operands(argument); exprt rhs=side_effect_expr_nondett(lhs.type()); rhs.location()=target->location; assignment->code=code_assignt(lhs, rhs); args++; break; } } } } else // non-const format string { for(unsigned i=argument_start_inx; i<arguments.size(); i++) { const typet &arg_type=ns.follow(arguments[i].type()); // Note: is_string_type() is a `good guess' here. Actually // any of the pointers could point into an array. But it // would suck if we had to invalidate all variables. // Luckily this case isn't needed too often. if(is_string_type(arg_type)) { goto_programt::targett assertion=dest.add_instruction(); assertion->location=target->location; assertion->location.set("property", "string"); std::string comment("format string buffer overflow in "); comment += function_name; assertion->location.set("comment", comment); // as we don't know any field width for the %s that // should be here during runtime, we just report a // possibly false positive assertion->make_assertion(false_exprt()); invalidate_buffer(dest, target, arguments[i], arg_type, 0); } else { goto_programt::targett assignment = dest.add_instruction(ASSIGN); assignment->location=target->location; exprt lhs("dereference", arg_type.subtype()); lhs.copy_to_operands(arguments[i]); exprt rhs=side_effect_expr_nondett(lhs.type()); rhs.location()=target->location; assignment->code=code_assignt(lhs, rhs); } } } }
codet java_bytecode_convertt::convert_instructions( const instructionst &instructions, const code_typet &method_type) { // Run a worklist algorithm, assuming that the bytecode has not // been tampered with. See "Leroy, X. (2003). Java bytecode // verification: algorithms and formalizations. Journal of Automated // Reasoning, 30(3-4), 235-269." for a more complete treatment. // first pass: get targets and map addresses to instructions struct converted_instructiont { converted_instructiont( const instructionst::const_iterator &it, const codet &_code):source(it), code(_code), done(false) { } instructionst::const_iterator source; std::list<unsigned> successors; std::set<unsigned> predecessors; codet code; stackt stack; bool done; }; typedef std::map<unsigned, converted_instructiont> address_mapt; address_mapt address_map; std::set<unsigned> targets; for(instructionst::const_iterator i_it=instructions.begin(); i_it!=instructions.end(); i_it++) { std::pair<address_mapt::iterator, bool> a_entry= address_map.insert(std::make_pair( i_it->address, converted_instructiont(i_it, code_skipt()))); assert(a_entry.second); // addresses are strictly increasing, hence we must have inserted // a new maximal key assert(a_entry.first==--address_map.end()); if(i_it->statement!="goto" && i_it->statement!="return" && !(i_it->statement==patternt("?return")) && i_it->statement!="athrow") { instructionst::const_iterator next=i_it; if(++next!=instructions.end()) a_entry.first->second.successors.push_back(next->address); } if(i_it->statement=="goto" || i_it->statement==patternt("if_?cmp??") || i_it->statement==patternt("if??") || i_it->statement=="ifnonnull" || i_it->statement=="ifnull") { assert(!i_it->args.empty()); const unsigned target=safe_string2unsigned( id2string(to_constant_expr(i_it->args[0]).get_value())); targets.insert(target); a_entry.first->second.successors.push_back(target); } else if(i_it->statement=="tableswitch" || i_it->statement=="lookupswitch") { bool is_label=true; for(instructiont::argst::const_iterator a_it=i_it->args.begin(); a_it!=i_it->args.end(); a_it++, is_label=!is_label) { if(is_label) { const unsigned target=safe_string2unsigned( id2string(to_constant_expr(*a_it).get_value())); targets.insert(target); a_entry.first->second.successors.push_back(target); } } } } for(address_mapt::iterator it=address_map.begin(); it!=address_map.end(); ++it) { for(unsigned s : it->second.successors) { address_mapt::iterator a_it=address_map.find(s); assert(a_it!=address_map.end()); a_it->second.predecessors.insert(it->first); } } std::set<unsigned> working_set; if(!instructions.empty()) working_set.insert(instructions.front().address); while(!working_set.empty()) { std::set<unsigned>::iterator cur=working_set.begin(); address_mapt::iterator a_it=address_map.find(*cur); assert(a_it!=address_map.end()); working_set.erase(cur); if(a_it->second.done) continue; working_set.insert(a_it->second.successors.begin(), a_it->second.successors.end()); instructionst::const_iterator i_it=a_it->second.source; stack.swap(a_it->second.stack); a_it->second.stack.clear(); codet &c=a_it->second.code; assert(stack.empty() || a_it->second.predecessors.size()<=1 || has_prefix(stack.front().get_string(ID_C_base_name), "$stack")); irep_idt statement=i_it->statement; exprt arg0=i_it->args.size()>=1?i_it->args[0]:nil_exprt(); exprt arg1=i_it->args.size()>=2?i_it->args[1]:nil_exprt(); const bytecode_infot &bytecode_info=get_bytecode_info(statement); // deal with _idx suffixes if(statement.size()>=2 && statement[statement.size()-2]=='_' && isdigit(statement[statement.size()-1])) { arg0=constant_exprt( std::string(id2string(statement), statement.size()-1, 1), integer_typet()); statement=std::string(id2string(statement), 0, statement.size()-2); } exprt::operandst op=pop(bytecode_info.pop); exprt::operandst results; results.resize(bytecode_info.push, nil_exprt()); if(statement=="aconst_null") { assert(results.size()==1); results[0]=gen_zero(java_reference_type(void_typet())); } else if(statement=="athrow") { assert(op.size()==1 && results.size()==1); side_effect_expr_throwt throw_expr; throw_expr.add_source_location()=i_it->source_location; throw_expr.copy_to_operands(op[0]); c=code_expressiont(throw_expr); results[0]=op[0]; } else if(statement=="checkcast") { // checkcast throws an exception in case a cast of object // on stack to given type fails. // The stack isn't modified. assert(op.size()==1 && results.size()==1); results[0]=op[0]; } else if(statement=="invokedynamic") { // not used in Java code_typet &code_type=to_code_type(arg0.type()); const code_typet::parameterst ¶meters(code_type.parameters()); pop(parameters.size()); const typet &return_type=code_type.return_type(); if(return_type.id()!=ID_empty) { results.resize(1); results[0]=nil_exprt(); } } else if(statement=="invokeinterface" || statement=="invokespecial" || statement=="invokevirtual" || statement=="invokestatic") { const bool use_this(statement != "invokestatic"); const bool is_virtual( statement == "invokevirtual" || statement == "invokeinterface"); code_typet &code_type=to_code_type(arg0.type()); code_typet::parameterst ¶meters(code_type.parameters()); if(use_this) { if(parameters.empty() || !parameters[0].get_this()) { const empty_typet empty; pointer_typet object_ref_type(empty); code_typet::parametert this_p(object_ref_type); this_p.set_this(); this_p.set_base_name("this"); parameters.insert(parameters.begin(), this_p); } } code_function_callt call; call.add_source_location()=i_it->source_location; call.arguments() = pop(parameters.size()); // double-check a bit if(use_this) { const exprt &this_arg=call.arguments().front(); assert(this_arg.type().id()==ID_pointer); } // do some type adjustment for the arguments, // as Java promotes arguments for(unsigned i=0; i<parameters.size(); i++) { const typet &type=parameters[i].type(); if(type==java_boolean_type() || type==java_char_type() || type==java_byte_type() || type==java_short_type()) { assert(i<call.arguments().size()); call.arguments()[i].make_typecast(type); } } // do some type adjustment for return values const typet &return_type=code_type.return_type(); if(return_type.id()!=ID_empty) { // return types are promoted in Java call.lhs()=tmp_variable("return", return_type); exprt promoted=java_bytecode_promotion(call.lhs()); results.resize(1); results[0]=promoted; } assert(arg0.id()==ID_virtual_function); // does the function symbol exist? irep_idt id=arg0.get(ID_identifier); if(symbol_table.symbols.find(id)==symbol_table.symbols.end()) { // no, create stub symbolt symbol; symbol.name=id; symbol.base_name=arg0.get(ID_C_base_name); symbol.type=arg0.type(); symbol.value.make_nil(); symbol.mode=ID_java; symbol_table.add(symbol); } if(is_virtual) { // dynamic binding assert(use_this); assert(!call.arguments().empty()); call.function()=arg0; } else { // static binding /*if(id == "java::java.lang.String.charAt:(I)C") call.function()=symbol_exprt("java::__CPROVER_uninterpreted_char_at", arg0.type()); else*/ call.function()=symbol_exprt(arg0.get(ID_identifier), arg0.type()); } call.function().add_source_location()=i_it->source_location; c = call; } else if(statement=="return") { assert(op.empty() && results.empty()); c=code_returnt(); } else if(statement==patternt("?return")) { // Return types are promoted in java, so this might need // conversion. assert(op.size()==1 && results.empty()); exprt r=op[0]; if(r.type()!=method_return_type) r=typecast_exprt(r, method_return_type); c=code_returnt(r); } else if(statement==patternt("?astore")) { assert(op.size()==3 && results.empty()); char type_char=statement[0]; exprt pointer= typecast_exprt(op[0], java_array_type(type_char)); const dereference_exprt deref(pointer, pointer.type().subtype()); const member_exprt data_ptr( deref, "data", pointer_typet(java_type_from_char(type_char))); plus_exprt data_plus_offset(data_ptr, op[1], data_ptr.type()); typet element_type=data_ptr.type().subtype(); const dereference_exprt element(data_plus_offset, element_type); c=code_assignt(element, op[2]); } else if(statement==patternt("?store")) { // store value into some local variable assert(op.size()==1 && results.empty()); exprt var=variable(arg0, statement[0]); const bool is_array('a' == statement[0]); if(is_array) var.type()=op[0].type(); c=code_assignt(var, op[0]); } else if(statement==patternt("?aload")) { assert(op.size() == 2 && results.size() == 1); char type_char=statement[0]; exprt pointer= typecast_exprt(op[0], java_array_type(type_char)); const dereference_exprt deref(pointer, pointer.type().subtype()); const member_exprt data_ptr( deref, "data", pointer_typet(java_type_from_char(type_char))); plus_exprt data_plus_offset(data_ptr, op[1], data_ptr.type()); typet element_type=data_ptr.type().subtype(); dereference_exprt element(data_plus_offset, element_type); results[0]=java_bytecode_promotion(element); } else if(statement==patternt("?load")) { // load a value from a local variable results[0]=variable(arg0, statement[0]); } else if(statement=="ldc" || statement=="ldc_w" || statement=="ldc2" || statement=="ldc2_w") { assert(op.empty() && results.size()==1); // 1) Pushing a String causes a reference to a java.lang.String object // to be constructed and pushed onto the operand stack. // 2) Pushing an int or a float causes a primitive value to be pushed // onto the stack. // 3) Pushing a Class constant causes a reference to a java.lang.Class // to be pushed onto the operand stack if(arg0.id()==ID_java_string_literal) { // these need to be references to java.lang.String results[0]=arg0; symbol_typet string_type("java::java.lang.String"); results[0].type()=pointer_typet(string_type); } else if(arg0.id()==ID_type) { irep_idt class_id=arg0.type().get(ID_identifier); symbol_typet java_lang_Class("java::java.lang.Class"); symbol_exprt symbol_expr(id2string(class_id)+"@class_model", java_lang_Class); address_of_exprt address_of_expr(symbol_expr); results[0]=address_of_expr; } else if(arg0.id()==ID_constant) { results[0]=arg0; } else { error() << "unexpected ldc argument" << eom; throw 0; } } else if(statement=="goto" || statement=="goto_w") { assert(op.empty() && results.empty()); irep_idt number=to_constant_expr(arg0).get_value(); code_gotot code_goto(label(number)); c=code_goto; } else if(statement=="iconst_m1") { assert(results.size()==1); results[0]=from_integer(-1, java_int_type()); } else if(statement==patternt("?const")) { assert(results.size() == 1); const char type_char=statement[0]; const bool is_double('d' == type_char); const bool is_float('f' == type_char); if(is_double || is_float) { const ieee_float_spect spec( is_float ? ieee_float_spect::single_precision() : ieee_float_spect::double_precision()); ieee_floatt value(spec); const typet &arg_type(arg0.type()); if(ID_integer == arg_type.id()) value.from_integer(arg0.get_int(ID_value)); else value.from_expr(to_constant_expr(arg0)); results[0] = value.to_expr(); } else { const unsigned int value(arg0.get_unsigned_int(ID_value)); const typet type=java_type_from_char(statement[0]); results[0] = as_number(value, type); } } else if(statement==patternt("?ipush")) { assert(results.size()==1); results[0]=typecast_exprt(arg0, java_int_type()); } else if(statement==patternt("if_?cmp??")) { irep_idt number=to_constant_expr(arg0).get_value(); assert(op.size()==2 && results.empty()); code_ifthenelset code_branch; const irep_idt cmp_op=get_if_cmp_operator(statement); binary_relation_exprt condition(op[0], cmp_op, op[1]); cast_if_necessary(condition); code_branch.cond()=condition; code_branch.then_case()=code_gotot(label(number)); code_branch.then_case().add_source_location()=i_it->source_location; code_branch.add_source_location()=i_it->source_location; c=code_branch; } else if(statement==patternt("if??")) { const irep_idt id= statement=="ifeq"?ID_equal: statement=="ifne"?ID_notequal: statement=="iflt"?ID_lt: statement=="ifge"?ID_ge: statement=="ifgt"?ID_gt: statement=="ifle"?ID_le: (assert(false), ""); irep_idt number=to_constant_expr(arg0).get_value(); assert(op.size()==1 && results.empty()); code_ifthenelset code_branch; code_branch.cond()=binary_relation_exprt(op[0], id, gen_zero(op[0].type())); code_branch.cond().add_source_location()=i_it->source_location; code_branch.then_case()=code_gotot(label(number)); code_branch.then_case().add_source_location()=i_it->source_location; code_branch.add_source_location()=i_it->source_location; c=code_branch; } else if(statement==patternt("ifnonnull")) { irep_idt number=to_constant_expr(arg0).get_value(); assert(op.size()==1 && results.empty()); code_ifthenelset code_branch; const typecast_exprt lhs(op[0], pointer_typet()); const exprt rhs(gen_zero(lhs.type())); code_branch.cond()=binary_relation_exprt(lhs, ID_notequal, rhs); code_branch.then_case()=code_gotot(label(number)); code_branch.then_case().add_source_location()=i_it->source_location; code_branch.add_source_location()=i_it->source_location; c=code_branch; } else if(statement==patternt("ifnull")) { assert(op.size()==1 && results.empty()); irep_idt number=to_constant_expr(arg0).get_value(); code_ifthenelset code_branch; const typecast_exprt lhs(op[0], pointer_typet(empty_typet())); const exprt rhs(gen_zero(lhs.type())); code_branch.cond()=binary_relation_exprt(lhs, ID_equal, rhs); code_branch.then_case()=code_gotot(label(number)); code_branch.then_case().add_source_location()=i_it->source_location; code_branch.add_source_location()=i_it->source_location; c=code_branch; } else if(statement=="iinc") { code_assignt code_assign; code_assign.lhs()=variable(arg0, 'i'); code_assign.rhs()=plus_exprt( variable(arg0, 'i'), typecast_exprt(arg1, java_int_type())); c=code_assign; } else if(statement==patternt("?xor")) { assert(op.size()==2 && results.size()==1); results[0]=bitxor_exprt(op[0], op[1]); } else if(statement==patternt("?or")) { assert(op.size()==2 && results.size()==1); results[0]=bitor_exprt(op[0], op[1]); } else if(statement==patternt("?and")) { assert(op.size()==2 && results.size()==1); results[0]=bitand_exprt(op[0], op[1]); } else if(statement==patternt("?shl")) { assert(op.size()==2 && results.size()==1); results[0]=shl_exprt(op[0], op[1]); } else if(statement==patternt("?shr")) { assert(op.size()==2 && results.size()==1); results[0]=ashr_exprt(op[0], op[1]); } else if(statement==patternt("?ushr")) { assert(op.size()==2 && results.size()==1); const typet type(java_type_from_char(statement[0])); const unsigned int width(type.get_unsigned_int(ID_width)); typet target=unsigned_long_int_type(); target.set(ID_width, width); const typecast_exprt lhs(op[0], target); const typecast_exprt rhs(op[1], target); results[0]=lshr_exprt(lhs, rhs); } else if(statement==patternt("?add")) { assert(op.size()==2 && results.size()==1); results[0]=plus_exprt(op[0], op[1]); } else if(statement==patternt("?sub")) { assert(op.size()==2 && results.size()==1); results[0]=minus_exprt(op[0], op[1]); } else if(statement==patternt("?div")) { assert(op.size()==2 && results.size()==1); results[0]=div_exprt(op[0], op[1]); } else if(statement==patternt("?mul")) { assert(op.size()==2 && results.size()==1); results[0]=mult_exprt(op[0], op[1]); } else if(statement==patternt("?neg")) { assert(op.size()==1 && results.size()==1); results[0]=unary_minus_exprt(op[0], op[0].type()); } else if(statement==patternt("?rem")) { assert(op.size()==2 && results.size()==1); if(statement=="frem" || statement=="drem") results[0]=rem_exprt(op[0], op[1]); else results[0]=mod_exprt(op[0], op[1]); } else if(statement==patternt("?cmp")) { assert(op.size() == 2 && results.size() == 1); // The integer result on the stack is: // 0 if op[0] equals op[1] // -1 if op[0] is less than op[1] // 1 if op[0] is greater than op[1] const typet t=java_int_type(); results[0]= if_exprt(binary_relation_exprt(op[0], ID_equal, op[1]), gen_zero(t), if_exprt(binary_relation_exprt(op[0], ID_gt, op[1]), from_integer(1, t), from_integer(-1, t))); } else if(statement==patternt("?cmp?")) { assert(op.size()==2 && results.size()==1); const floatbv_typet type(to_floatbv_type(java_type_from_char(statement[0]))); const ieee_float_spect spec(type); const ieee_floatt nan(ieee_floatt::NaN(spec)); const constant_exprt nan_expr(nan.to_expr()); const int nan_value(statement[4] == 'l' ? -1 : 1); const typet result_type(java_int_type()); const exprt nan_result(from_integer(nan_value, result_type)); // (value1 == NaN || value2 == NaN) ? nan_value : value1 < value2 ? -1 : value2 < value1 1 ? 1 : 0; // (value1 == NaN || value2 == NaN) ? nan_value : value1 == value2 ? 0 : value1 < value2 -1 ? 1 : 0; results[0]= if_exprt(or_exprt(ieee_float_equal_exprt(nan_expr, op[0]), ieee_float_equal_exprt(nan_expr, op[1])), nan_result, if_exprt(ieee_float_equal_exprt(op[0], op[1]), gen_zero(result_type), if_exprt(binary_relation_exprt(op[0], ID_lt, op[1]), from_integer(-1, result_type), from_integer(1, result_type)))); } else if(statement==patternt("?cmpl")) { assert(op.size()==2 && results.size()==1); results[0]=binary_relation_exprt(op[0], ID_lt, op[1]); } else if(statement=="dup") { assert(op.size()==1 && results.size()==2); results[0]=results[1]=op[0]; } else if(statement=="dup_x1") { assert(op.size()==2 && results.size()==3); results[0]=op[1]; results[1]=op[0]; results[2]=op[1]; } else if(statement=="dup_x2") { assert(op.size()==3 && results.size()==4); results[0]=op[2]; results[1]=op[0]; results[2]=op[1]; results[3]=op[2]; } // dup2* behaviour depends on the size of the operands on the // stack else if(statement=="dup2") { assert(!stack.empty() && results.empty()); if(stack.back().type().get_unsigned_int(ID_width)==32) op=pop(2); else op=pop(1); results.insert(results.end(), op.begin(), op.end()); results.insert(results.end(), op.begin(), op.end()); } else if(statement=="dup2_x1") { assert(!stack.empty() && results.empty()); if(stack.back().type().get_unsigned_int(ID_width)==32) op=pop(3); else op=pop(2); results.insert(results.end(), op.begin()+1, op.end()); results.insert(results.end(), op.begin(), op.end()); } else if(statement=="dup2_x2") { assert(!stack.empty() && results.empty()); if(stack.back().type().get_unsigned_int(ID_width)==32) op=pop(2); else op=pop(1); assert(!stack.empty()); exprt::operandst op2; if(stack.back().type().get_unsigned_int(ID_width)==32) op2=pop(2); else op2=pop(1); results.insert(results.end(), op.begin(), op.end()); results.insert(results.end(), op2.begin(), op2.end()); results.insert(results.end(), op.begin(), op.end()); } else if(statement=="dconst") { assert(op.empty() && results.size()==1); } else if(statement=="fconst") { assert(op.empty() && results.size()==1); } else if(statement=="getfield") { assert(op.size()==1 && results.size()==1); results[0]=to_member(op[0], arg0); } else if(statement=="getstatic") { assert(op.empty() && results.size()==1); symbol_exprt symbol_expr(arg0.type()); symbol_expr.set_identifier(arg0.get_string(ID_class)+"."+arg0.get_string(ID_component_name)); results[0]=symbol_expr; } else if(statement=="putfield") { assert(op.size()==2 && results.size()==0); c = code_assignt(to_member(op[0], arg0), op[1]); } else if(statement=="putstatic") { assert(op.size()==1 && results.empty()); symbol_exprt symbol_expr(arg0.type()); symbol_expr.set_identifier(arg0.get_string(ID_class)+"."+arg0.get_string(ID_component_name)); c=code_assignt(symbol_expr, op[0]); } else if(statement==patternt("?2?")) // i2c etc. { assert(op.size()==1 && results.size()==1); results[0]=typecast_exprt(op[0], java_type_from_char(statement[2])); } else if(statement=="new") { // use temporary since the stack symbol might get duplicated assert(op.empty() && results.size()==1); const pointer_typet ref_type(arg0.type()); exprt java_new_expr=side_effect_exprt(ID_java_new, ref_type); if(!i_it->source_location.get_line().empty()) java_new_expr.add_source_location()=i_it->source_location; const exprt tmp=tmp_variable("new", ref_type); c=code_assignt(tmp, java_new_expr); results[0]=tmp; } else if(statement=="newarray" || statement=="anewarray") { // the op is the array size assert(op.size()==1 && results.size()==1); char element_type; if(statement=="newarray") { irep_idt id=arg0.type().id(); if(id==ID_bool) element_type='z'; else if(id==ID_char) element_type='c'; else if(id==ID_float) element_type='f'; else if(id==ID_double) element_type='d'; else if(id==ID_byte) element_type='b'; else if(id==ID_short) element_type='s'; else if(id==ID_int) element_type='i'; else if(id==ID_long) element_type='j'; else element_type='?'; } else element_type='a'; const pointer_typet ref_type=java_array_type(element_type); side_effect_exprt java_new_array(ID_java_new_array, ref_type); java_new_array.copy_to_operands(op[0]); if(!i_it->source_location.get_line().empty()) java_new_array.add_source_location()=i_it->source_location; const exprt tmp=tmp_variable("newarray", ref_type); c=code_assignt(tmp, java_new_array); results[0]=tmp; } else if(statement=="multianewarray") { // The first argument is the type, the second argument is the dimension. // The size of each dimension is on the stack. irep_idt number=to_constant_expr(arg1).get_value(); unsigned dimension=safe_c_str2unsigned(number.c_str()); op=pop(dimension); assert(results.size()==1); // arg0.type() const pointer_typet ref_type=java_array_type('a'); side_effect_exprt java_new_array(ID_java_new_array, ref_type); java_new_array.operands()=op; if(!i_it->source_location.get_line().empty()) java_new_array.add_source_location()=i_it->source_location; const exprt tmp=tmp_variable("newarray", ref_type); c=code_assignt(tmp, java_new_array); results[0]=tmp; } else if(statement=="arraylength") { assert(op.size()==1 && results.size()==1); exprt pointer= typecast_exprt(op[0], java_array_type(statement[0])); const dereference_exprt array(pointer, pointer.type().subtype()); assert(pointer.type().subtype().id()==ID_symbol); const member_exprt length(array, "length", java_int_type()); results[0]=length; } else if(statement=="tableswitch" || statement=="lookupswitch") { assert(op.size()==1 && results.size()==0); // we turn into switch-case code_switcht code_switch; code_switch.add_source_location()=i_it->source_location; code_switch.value()=op[0]; code_blockt code_block; code_block.add_source_location()=i_it->source_location; bool is_label=true; for(instructiont::argst::const_iterator a_it=i_it->args.begin(); a_it!=i_it->args.end(); a_it++, is_label=!is_label) { if(is_label) { code_switch_caset code_case; code_case.add_source_location()=i_it->source_location; irep_idt number=to_constant_expr(*a_it).get_value(); code_case.code()=code_gotot(label(number)); code_case.code().add_source_location()=i_it->source_location; if(a_it==i_it->args.begin()) code_case.set_default(); else { instructiont::argst::const_iterator prev=a_it; prev--; code_case.case_op()=typecast_exprt(*prev, op[0].type()); code_case.case_op().add_source_location()=i_it->source_location; } code_block.add(code_case); } } code_switch.body()=code_block; c=code_switch; } else if(statement=="pop" || statement=="pop2") { // these are skips c=code_skipt(); // pop2 removes two single-word items from the stack (e.g. two // integers, or an integer and an object reference) or one // two-word item (i.e. a double or a long). // http://cs.au.dk/~mis/dOvs/jvmspec/ref-pop2.html if(statement=="pop2" && op[0].type().get_unsigned_int(ID_width)==32) pop(1); } else if(statement=="instanceof") { assert(op.size()==1 && results.size()==1); results[0]= binary_predicate_exprt(op[0], "java_instanceof", arg0); } else { c=codet(statement); c.operands()=op; } if(!i_it->source_location.get_line().empty()) c.add_source_location()=i_it->source_location; push(results); a_it->second.done=true; for(std::list<unsigned>::iterator it=a_it->second.successors.begin(); it!=a_it->second.successors.end(); ++it) { address_mapt::iterator a_it2=address_map.find(*it); assert(a_it2!=address_map.end()); if(!stack.empty() && a_it2->second.predecessors.size()>1) { // copy into temporaries code_blockt more_code; // introduce temporaries when successor is seen for the first // time if(a_it2->second.stack.empty()) { for(stackt::iterator s_it=stack.begin(); s_it!=stack.end(); ++s_it) { symbol_exprt lhs=tmp_variable("$stack", s_it->type()); code_assignt a(lhs, *s_it); more_code.copy_to_operands(a); s_it->swap(lhs); } } else { assert(a_it2->second.stack.size()==stack.size()); stackt::const_iterator os_it=a_it2->second.stack.begin(); for(stackt::iterator s_it=stack.begin(); s_it!=stack.end(); ++s_it) { assert(has_prefix(os_it->get_string(ID_C_base_name), "$stack")); symbol_exprt lhs=to_symbol_expr(*os_it); code_assignt a(lhs, *s_it); more_code.copy_to_operands(a); s_it->swap(lhs); ++os_it; } } if(results.empty()) { more_code.copy_to_operands(c); c.swap(more_code); } else { c.make_block(); forall_operands(o_it, more_code) c.copy_to_operands(*o_it); } } a_it2->second.stack=stack; } } // TODO: add exception handlers from exception table // review successor computation of athrow! code_blockt code; // temporaries for(const auto & var : tmp_vars) { code.add(code_declt(var)); } for(const auto & it : address_map) { const unsigned address=it.first; assert(it.first==it.second.source->address); const codet &c=it.second.code; if(targets.find(address)!=targets.end()) code.add(code_labelt(label(i2string(address)), c)); else if(c.get_statement()!=ID_skip) code.add(c); } return code; }
void goto_checkt::nan_check( const exprt &expr, const guardt &guard) { if(!enable_nan_check) return; // first, check type if(expr.type().id()!=ID_floatbv) return; if(expr.id()!=ID_plus && expr.id()!=ID_mult && expr.id()!=ID_div && expr.id()!=ID_minus) return; // add NaN subgoal exprt isnan; if(expr.id()==ID_div) { assert(expr.operands().size()==2); // there a two ways to get a new NaN on division: // 0/0 = NaN and x/inf = NaN // (note that x/0 = +-inf for x!=0 and x!=inf) exprt zero_div_zero=and_exprt( ieee_float_equal_exprt(expr.op0(), gen_zero(expr.op0().type())), ieee_float_equal_exprt(expr.op1(), gen_zero(expr.op1().type()))); exprt div_inf=unary_exprt(ID_isinf, expr.op1(), bool_typet()); isnan=or_exprt(zero_div_zero, div_inf); } else if(expr.id()==ID_mult) { if(expr.operands().size()>=3) return nan_check(make_binary(expr), guard); assert(expr.operands().size()==2); // Inf * 0 is NaN exprt inf_times_zero=and_exprt( unary_exprt(ID_isinf, expr.op0(), bool_typet()), ieee_float_equal_exprt(expr.op1(), gen_zero(expr.op1().type()))); exprt zero_times_inf=and_exprt( ieee_float_equal_exprt(expr.op1(), gen_zero(expr.op1().type())), unary_exprt(ID_isinf, expr.op0(), bool_typet())); isnan=or_exprt(inf_times_zero, zero_times_inf); } else if(expr.id()==ID_plus) { if(expr.operands().size()>=3) return nan_check(make_binary(expr), guard); assert(expr.operands().size()==2); // -inf + +inf = NaN and +inf + -inf = NaN, // i.e., signs differ ieee_float_spect spec=ieee_float_spect(to_floatbv_type(expr.type())); exprt plus_inf=ieee_floatt::plus_infinity(spec).to_expr(); exprt minus_inf=ieee_floatt::minus_infinity(spec).to_expr(); isnan=or_exprt( and_exprt(equal_exprt(expr.op0(), minus_inf), equal_exprt(expr.op1(), plus_inf)), and_exprt(equal_exprt(expr.op0(), plus_inf), equal_exprt(expr.op1(), minus_inf))); } else if(expr.id()==ID_minus) { assert(expr.operands().size()==2); // +inf - +inf = NaN and -inf - -inf = NaN, // i.e., signs match ieee_float_spect spec=ieee_float_spect(to_floatbv_type(expr.type())); exprt plus_inf=ieee_floatt::plus_infinity(spec).to_expr(); exprt minus_inf=ieee_floatt::minus_infinity(spec).to_expr(); isnan=or_exprt( and_exprt(equal_exprt(expr.op0(), plus_inf), equal_exprt(expr.op1(), plus_inf)), and_exprt(equal_exprt(expr.op0(), minus_inf), equal_exprt(expr.op1(), minus_inf))); } else assert(false); isnan.make_not(); add_guarded_claim( isnan, "NaN on "+expr.id_string(), "NaN", expr.find_source_location(), expr, guard); }
bool ssa_may_alias( const exprt &e1, const exprt &e2, const namespacet &ns) { #ifdef DEBUG std::cout << "MAY ALIAS1 " << from_expr(ns, "", e1) << " " << from_expr(ns, "", e2) << "\n"; #endif // The same? if(e1==e2) return true; // Both symbol? if(e1.id()==ID_symbol && e2.id()==ID_symbol) { return to_symbol_expr(e1).get_identifier()== to_symbol_expr(e2).get_identifier(); } // __CPROVER symbols if(e1.id()==ID_symbol && has_prefix( id2string(to_symbol_expr(e1).get_identifier()), CPROVER_PREFIX)) return false; if(e2.id()==ID_symbol && has_prefix( id2string(to_symbol_expr(e2).get_identifier()), CPROVER_PREFIX)) return false; if(e1.id()==ID_symbol && has_suffix( id2string(to_symbol_expr(e1).get_identifier()), "#return_value")) return false; if(e2.id()==ID_symbol && has_suffix( id2string(to_symbol_expr(e2).get_identifier()), "#return_value")) return false; // Both member? if(e1.id()==ID_member && e2.id()==ID_member) { const member_exprt &m1=to_member_expr(e1); const member_exprt &m2=to_member_expr(e2); // same component? if(m1.get_component_name()!=m2.get_component_name()) return false; return ssa_may_alias(m1.struct_op(), m2.struct_op(), ns); } // Both index? if(e1.id()==ID_index && e2.id()==ID_index) { const index_exprt &i1=to_index_expr(e1); const index_exprt &i2=to_index_expr(e2); return ssa_may_alias(i1.array(), i2.array(), ns); } const typet &t1=ns.follow(e1.type()); const typet &t2=ns.follow(e2.type()); // If one is an array and the other not, consider the elements if(t1.id()==ID_array && t2.id()!=ID_array) if(ssa_may_alias( index_exprt(e1, gen_zero(index_type()), t1.subtype()), e2, ns)) return true; if(t2.id()==ID_array && t2.id()!=ID_array) if(ssa_may_alias( e1, index_exprt(e2, gen_zero(index_type()), t2.subtype()), ns)) return true; // Pointers only alias with other pointers, // which is a restriction. if(t1.id()==ID_pointer) return t2.id()==ID_pointer; if(t2.id()==ID_pointer) return t1.id()==ID_pointer; // Is one a scalar pointer? if(e1.id()==ID_dereference && (t1.id()==ID_signedbv || t1.id()==ID_unsignedbv || t1.id()==ID_floatbv)) return true; if(e2.id()==ID_dereference && (t2.id()==ID_signedbv || t2.id()==ID_unsignedbv || t1.id()==ID_floatbv)) return true; // Is one a pointer? if(e1.id()==ID_dereference || e2.id()==ID_dereference) { // look at the types // same type? if(base_type_eq(t1, t2, ns)) { return true; } // should consider further options, e.g., struct prefixes return false; } return false; // both different objects }
void string_instrumentationt::do_strerror( goto_programt &dest, goto_programt::targett it, code_function_callt &call) { if(call.lhs().is_nil()) { it->make_skip(); return; } irep_idt identifier_buf="c::__strerror_buffer"; irep_idt identifier_size="c::__strerror_buffer_size"; if(context.symbols.find(identifier_buf)==context.symbols.end()) { symbolt new_symbol_size; new_symbol_size.base_name="__strerror_buffer_size"; new_symbol_size.pretty_name=new_symbol_size.base_name; new_symbol_size.name=identifier_size; new_symbol_size.mode="C"; new_symbol_size.type=uint_type(); new_symbol_size.is_statevar=true; new_symbol_size.lvalue=true; new_symbol_size.static_lifetime=true; array_typet type; type.subtype()=char_type(); type.size()=symbol_expr(new_symbol_size); symbolt new_symbol_buf; new_symbol_buf.mode="C"; new_symbol_buf.type=type; new_symbol_buf.is_statevar=true; new_symbol_buf.lvalue=true; new_symbol_buf.static_lifetime=true; new_symbol_buf.base_name="__strerror_buffer"; new_symbol_buf.pretty_name=new_symbol_buf.base_name; new_symbol_buf.name="c::"+id2string(new_symbol_buf.base_name); context.move(new_symbol_buf); context.move(new_symbol_size); } const symbolt &symbol_size=ns.lookup(identifier_size); const symbolt &symbol_buf=ns.lookup(identifier_buf); goto_programt tmp; { goto_programt::targett assignment1=tmp.add_instruction(ASSIGN); exprt nondet_size=side_effect_expr_nondett(uint_type()); assignment1->code=code_assignt(symbol_expr(symbol_size), nondet_size); assignment1->location=it->location; goto_programt::targett assumption1=tmp.add_instruction(); assumption1->make_assumption(binary_relation_exprt( symbol_expr(symbol_size), "notequal", gen_zero(symbol_size.type))); assumption1->location=it->location; } // return a pointer to some magic buffer exprt index=exprt("index", char_type()); index.copy_to_operands(symbol_expr(symbol_buf), gen_zero(uint_type())); exprt ptr=exprt("address_of", pointer_typet()); ptr.type().subtype()=char_type(); ptr.copy_to_operands(index); // make that zero-terminated { goto_programt::targett assignment2=tmp.add_instruction(ASSIGN); assignment2->code=code_assignt(is_zero_string(ptr, true), true_exprt()); assignment2->location=it->location; } // assign address { goto_programt::targett assignment3=tmp.add_instruction(ASSIGN); exprt rhs=ptr; make_type(rhs, call.lhs().type()); assignment3->code=code_assignt(call.lhs(), rhs); assignment3->location=it->location; } it->make_skip(); dest.insert_before_swap(it, tmp); }