void java_bytecode_parsert::rconstant_pool() { u2 constant_pool_count=read_u2(); if(constant_pool_count==0) { error() << "invalid constant_pool_count" << eom; throw 0; } constant_pool.resize(constant_pool_count); for(constant_poolt::iterator it=constant_pool.begin(); it!=constant_pool.end(); it++) { // the first entry isn't used if(it==constant_pool.begin()) continue; it->tag=read_u1(); switch(it->tag) { case CONSTANT_Class: it->ref1=read_u2(); break; case CONSTANT_Fieldref: case CONSTANT_Methodref: case CONSTANT_InterfaceMethodref: case CONSTANT_NameAndType: case CONSTANT_InvokeDynamic: it->ref1=read_u2(); it->ref2=read_u2(); break; case CONSTANT_String: case CONSTANT_MethodType: it->ref1=read_u2(); break; case CONSTANT_Integer: case CONSTANT_Float: it->number=read_u4(); break; case CONSTANT_Long: case CONSTANT_Double: it->number=read_u8(); // Eight-byte constants take up two entires // in the constant_pool table, for annoying this programmer. if(it==constant_pool.end()) { error() << "invalid double entry" << eom; throw 0; } it++; it->tag=0; break; case CONSTANT_Utf8: { u2 bytes=read_u2(); std::string s; s.resize(bytes); for(std::string::iterator s_it=s.begin(); s_it!=s.end(); s_it++) *s_it=read_u1(); it->s=s; // hashes } break; case CONSTANT_MethodHandle: it->ref1=read_u1(); it->ref2=read_u2(); break; default: error() << "unknown constant pool entry (" << it->tag << ")" << eom; throw 0; } } // we do a bit of post-processing after we have them all for(constant_poolt::iterator it=constant_pool.begin(); it!=constant_pool.end(); it++) { // the first entry isn't used if(it==constant_pool.begin()) continue; switch(it->tag) { case CONSTANT_Class: { const std::string &s=id2string(pool_entry(it->ref1).s); it->expr=type_exprt(java_classname(s)); } break; case CONSTANT_Fieldref: { const pool_entryt &nameandtype_entry=pool_entry(it->ref2); const pool_entryt &name_entry=pool_entry(nameandtype_entry.ref1); const pool_entryt &class_entry=pool_entry(it->ref1); const pool_entryt &class_name_entry=pool_entry(class_entry.ref1); typet type=type_entry(nameandtype_entry.ref2); symbol_typet class_symbol= java_classname(id2string(class_name_entry.s)); exprt fieldref("fieldref", type); fieldref.set(ID_class, class_symbol.get_identifier()); fieldref.set(ID_component_name, name_entry.s); it->expr=fieldref; } break; case CONSTANT_Methodref: case CONSTANT_InterfaceMethodref: { const pool_entryt &nameandtype_entry=pool_entry(it->ref2); const pool_entryt &name_entry=pool_entry(nameandtype_entry.ref1); const pool_entryt &class_entry=pool_entry(it->ref1); const pool_entryt &class_name_entry=pool_entry(class_entry.ref1); typet type=type_entry(nameandtype_entry.ref2); symbol_typet class_symbol= java_classname(id2string(class_name_entry.s)); irep_idt component_name= id2string(name_entry.s)+ ":"+id2string(pool_entry(nameandtype_entry.ref2).s); irep_idt class_name= class_symbol.get_identifier(); irep_idt identifier= id2string(class_name)+"."+id2string(component_name); exprt virtual_function(ID_virtual_function, type); virtual_function.set(ID_component_name, component_name); virtual_function.set(ID_C_class, class_name); virtual_function.set(ID_C_base_name, name_entry.s); virtual_function.set(ID_identifier, identifier); it->expr=virtual_function; } break; case CONSTANT_String: { // ldc turns these into references to java.lang.String exprt string_literal(ID_java_string_literal); string_literal.set(ID_value, pool_entry(it->ref1).s); it->expr=string_literal; } break; case CONSTANT_Integer: it->expr=from_integer(it->number, java_int_type()); break; case CONSTANT_Float: { ieee_floatt value(ieee_float_spect::single_precision()); value.unpack(it->number); it->expr=value.to_expr(); } break; case CONSTANT_Long: it->expr=from_integer(it->number, java_long_type()); break; case CONSTANT_Double: { ieee_floatt value(ieee_float_spect::double_precision()); value.unpack(it->number); it->expr=value.to_expr(); } break; case CONSTANT_NameAndType: { it->expr.id("nameandtype"); } break; case CONSTANT_MethodHandle: { it->expr.id("methodhandle"); } break; case CONSTANT_MethodType: { it->expr.id("methodtype"); } break; case CONSTANT_InvokeDynamic: { it->expr.id("invokedynamic"); const pool_entryt &nameandtype_entry=pool_entry(it->ref2); typet type=type_entry(nameandtype_entry.ref2); it->expr.type()=type; } break; default:{}; } } }
void boolbvt::convert_byte_update( const byte_update_exprt &expr, bvt &bv) { if(expr.operands().size()!=3) throw "byte_update takes three operands"; const exprt &op=expr.op0(); const exprt &offset_expr=expr.offset(); const exprt &value=expr.value(); bool little_endian; if(expr.id()==ID_byte_update_little_endian) little_endian=true; else if(expr.id()==ID_byte_update_big_endian) little_endian=false; else assert(false); bv=convert_bv(op); const bvt &value_bv=convert_bv(value); std::size_t update_width=value_bv.size(); std::size_t byte_width=8; if(update_width>bv.size()) update_width=bv.size(); // see if the byte number is constant mp_integer index; if(!to_integer(offset_expr, index)) { // yes! mp_integer offset=index*8; if(offset+update_width>mp_integer(bv.size()) || offset<0) { // out of bounds } else { if(little_endian) { for(std::size_t i=0; i<update_width; i++) bv[integer2long(offset+i)]=value_bv[i]; } else { endianness_mapt map_op(op.type(), false, ns); endianness_mapt map_value(value.type(), false, ns); std::size_t offset_i=integer2unsigned(offset); for(std::size_t i=0; i<update_width; i++) bv[map_op.map_bit(offset_i+i)]=value_bv[map_value.map_bit(i)]; } } return; } // byte_update with variable index for(std::size_t offset=0; offset<bv.size(); offset+=byte_width) { // index condition equal_exprt equality; equality.lhs()=offset_expr; equality.rhs()=from_integer(offset/byte_width, offset_expr.type()); literalt equal=convert(equality); endianness_mapt map_op(op.type(), little_endian, ns); endianness_mapt map_value(value.type(), little_endian, ns); for(std::size_t bit=0; bit<update_width; bit++) if(offset+bit<bv.size()) { std::size_t bv_o=map_op.map_bit(offset+bit); std::size_t value_bv_o=map_value.map_bit(bit); bv[bv_o]=prop.lselect(equal, value_bv[value_bv_o], bv[bv_o]); } } }
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 c_typecheck_baset::typecheck_compound_body( struct_union_typet &type) { struct_union_typet::componentst &components=type.components(); struct_union_typet::componentst old_components; old_components.swap(components); // We get these as declarations! for(auto &decl : old_components) { // the arguments are member declarations or static assertions assert(decl.id()==ID_declaration); ansi_c_declarationt &declaration= to_ansi_c_declaration(static_cast<exprt &>(decl)); if(declaration.get_is_static_assert()) { struct_union_typet::componentt new_component; new_component.id(ID_static_assert); new_component.add_source_location()=declaration.source_location(); new_component.operands().swap(declaration.operands()); assert(new_component.operands().size()==2); components.push_back(new_component); } else { // do first half of type typecheck_type(declaration.type()); make_already_typechecked(declaration.type()); for(const auto &declarator : declaration.declarators()) { struct_union_typet::componentt new_component; new_component.add_source_location()= declarator.source_location(); new_component.set(ID_name, declarator.get_base_name()); new_component.set(ID_pretty_name, declarator.get_base_name()); new_component.type()=declaration.full_type(declarator); typecheck_type(new_component.type()); if(!is_complete_type(new_component.type()) && (new_component.type().id()!=ID_array || !to_array_type(new_component.type()).is_incomplete())) { error().source_location=new_component.type().source_location(); error() << "incomplete type not permitted here" << eom; throw 0; } components.push_back(new_component); } } } unsigned anon_member_counter=0; // scan for anonymous members, and name them for(auto &member : components) { if(member.get_name()!=irep_idt()) continue; member.set_name("$anon"+std::to_string(anon_member_counter++)); member.set_anonymous(true); } // scan for duplicate members { std::unordered_set<irep_idt, irep_id_hash> members; for(struct_union_typet::componentst::iterator it=components.begin(); it!=components.end(); it++) { if(!members.insert(it->get_name()).second) { error().source_location=it->source_location(); error() << "duplicate member '" << it->get_name() << '\'' << eom; throw 0; } } } // We allow an incomplete (C99) array as _last_ member! // Zero-length is allowed everywhere. if(type.id()==ID_struct || type.id()==ID_union) { for(struct_union_typet::componentst::iterator it=components.begin(); it!=components.end(); it++) { typet &c_type=it->type(); if(c_type.id()==ID_array && to_array_type(c_type).is_incomplete()) { // needs to be last member if(type.id()==ID_struct && it!=--components.end()) { error().source_location=it->source_location(); error() << "flexible struct member must be last member" << eom; throw 0; } // make it zero-length c_type.id(ID_array); c_type.set(ID_size, from_integer(0, index_type())); } } } // We may add some minimal padding inside and at // the end of structs and // as additional member for unions. if(type.id()==ID_struct) add_padding(to_struct_type(type), *this); else if(type.id()==ID_union) add_padding(to_union_type(type), *this); // Now remove zero-width bit-fields, these are just // for adjusting alignment. for(struct_typet::componentst::iterator it=components.begin(); it!=components.end(); ) // blank { if(it->type().id()==ID_c_bit_field && to_c_bit_field_type(it->type()).get_width()==0) it=components.erase(it); else it++; } // finally, check _Static_assert inside the compound for(struct_union_typet::componentst::iterator it=components.begin(); it!=components.end(); ) // no it++ { if(it->id()==ID_static_assert) { assert(it->operands().size()==2); exprt &assertion=it->op0(); typecheck_expr(assertion); typecheck_expr(it->op1()); assertion.make_typecast(bool_typet()); make_constant(assertion); if(assertion.is_false()) { error().source_location=it->source_location(); error() << "failed _Static_assert" << eom; throw 0; } else if(!assertion.is_true()) { // should warn/complain } it=components.erase(it); } else it++; } }
void dynamic_object_exprt::set_instance(unsigned int instance) { op0()=from_integer(instance, typet(ID_natural)); }
void convert_integer_literal( const std::string &src, exprt &dest, unsigned base) { bool is_unsigned=false; unsigned long_cnt=0; for(unsigned i=src.size(); i!=0; i--) { char ch=src[i-1]; if(ch=='u' || ch=='U') is_unsigned=true; else if(ch=='l' || ch=='L') long_cnt++; else break; } mp_integer value; if(base==10) { dest.value(src); value=string2integer(src, 10); } else if(base==8) { dest.hex_or_oct(true); value=string2integer(src, 8); } else { dest.hex_or_oct(true); std::string without_prefix(src, 2, std::string::npos); value=string2integer(without_prefix, 16); } typet type; irep_idt cpp_type; if(is_unsigned) type=typet("unsignedbv"); else type=typet("signedbv"); if(long_cnt==0) { type.width(config.ansi_c.int_width); if(!is_unsigned) cpp_type="signed_int"; else cpp_type="unsigned_int"; } else if(long_cnt==1) { type.width(config.ansi_c.long_int_width); if(!is_unsigned) cpp_type="signed_long_int"; else cpp_type="unsigned_long_int"; } else { type.width(config.ansi_c.long_long_int_width); if(!is_unsigned) cpp_type="signed_long_long_int"; else cpp_type="unsigned_long_long_int"; } type.set("#cpp_type", cpp_type); dest=from_integer(value, type); dest.cformat(src); }
void c_typecheck_baset::typecheck_type(typet &type) { // we first convert, and then check { ansi_c_convert_typet ansi_c_convert_type(get_message_handler()); ansi_c_convert_type.read(type); ansi_c_convert_type.write(type); } if(type.id()==ID_already_typechecked) { // need to preserve any qualifiers c_qualifierst c_qualifiers(type); c_qualifiers+=c_qualifierst(type.subtype()); bool packed=type.get_bool(ID_C_packed); exprt alignment=static_cast<const exprt &>(type.find(ID_C_alignment)); irept _typedef=type.find(ID_C_typedef); type=type.subtype(); c_qualifiers.write(type); if(packed) type.set(ID_C_packed, true); if(alignment.is_not_nil()) type.add(ID_C_alignment, alignment); if(_typedef.is_not_nil()) type.add(ID_C_typedef, _typedef); return; // done } // do we have alignment? if(type.find(ID_C_alignment).is_not_nil()) { exprt &alignment=static_cast<exprt &>(type.add(ID_C_alignment)); if(alignment.id()!=ID_default) { typecheck_expr(alignment); make_constant(alignment); } } if(type.id()==ID_code) typecheck_code_type(to_code_type(type)); else if(type.id()==ID_array) typecheck_array_type(to_array_type(type)); else if(type.id()==ID_pointer) typecheck_type(type.subtype()); else if(type.id()==ID_struct || type.id()==ID_union) typecheck_compound_type(to_struct_union_type(type)); else if(type.id()==ID_c_enum) typecheck_c_enum_type(type); else if(type.id()==ID_c_enum_tag) typecheck_c_enum_tag_type(to_c_enum_tag_type(type)); else if(type.id()==ID_c_bit_field) typecheck_c_bit_field_type(to_c_bit_field_type(type)); else if(type.id()==ID_typeof) typecheck_typeof_type(type); else if(type.id()==ID_symbol) typecheck_symbol_type(type); else if(type.id()==ID_vector) typecheck_vector_type(to_vector_type(type)); else if(type.id()==ID_custom_unsignedbv || type.id()==ID_custom_signedbv || type.id()==ID_custom_floatbv || type.id()==ID_custom_fixedbv) typecheck_custom_type(type); else if(type.id()==ID_gcc_attribute_mode) { // get that mode irep_idt mode=type.get(ID_size); // A list of all modes ist at // http://www.delorie.com/gnu/docs/gcc/gccint_53.html typecheck_type(type.subtype()); typet underlying_type=type.subtype(); // gcc allows this, but clang doesn't; it's a compiler hint only, // but we'll try to interpret it the GCC way if(underlying_type.id()==ID_c_enum_tag) { underlying_type= follow_tag(to_c_enum_tag_type(underlying_type)).subtype(); assert(underlying_type.id()==ID_signedbv || underlying_type.id()==ID_unsignedbv); } if(underlying_type.id()==ID_signedbv || underlying_type.id()==ID_unsignedbv) { bool is_signed=underlying_type.id()==ID_signedbv; typet result; if(mode=="__QI__") // 8 bits result=is_signed?signed_char_type():unsigned_char_type(); else if(mode=="__byte__") // 8 bits result=is_signed?signed_char_type():unsigned_char_type(); else if(mode=="__HI__") // 16 bits result=is_signed?signed_short_int_type():unsigned_short_int_type(); else if(mode=="__SI__") // 32 bits result=is_signed?signed_int_type():unsigned_int_type(); else if(mode=="__word__") // long int, we think result=is_signed?signed_long_int_type():unsigned_long_int_type(); else if(mode=="__pointer__") // we think this is size_t/ssize_t result=is_signed?signed_size_type():size_type(); else if(mode=="__DI__") // 64 bits { if(config.ansi_c.long_int_width==64) result=is_signed?signed_long_int_type():unsigned_long_int_type(); else { assert(config.ansi_c.long_long_int_width==64); result= is_signed?signed_long_long_int_type():unsigned_long_long_int_type(); } } else if(mode=="__TI__") // 128 bits result=is_signed?gcc_signed_int128_type():gcc_unsigned_int128_type(); else if(mode=="__V2SI__") // vector of 2 ints, deprecated by gcc result= vector_typet( is_signed?signed_int_type():unsigned_int_type(), from_integer(2, size_type())); else if(mode=="__V4SI__") // vector of 4 ints, deprecated by gcc result= vector_typet( is_signed?signed_int_type():unsigned_int_type(), from_integer(4, size_type())); else // give up, just use subtype result=type.subtype(); // save the location result.add_source_location()=type.source_location(); if(type.subtype().id()==ID_c_enum_tag) { const irep_idt &tag_name= to_c_enum_tag_type(type.subtype()).get_identifier(); symbol_tablet::symbolst::iterator entry= symbol_table.symbols.find(tag_name); assert(entry!=symbol_table.symbols.end()); entry->second.type.subtype()=result; } type=result; } else if(underlying_type.id()==ID_floatbv) { typet result; if(mode=="__SF__") // 32 bits result=float_type(); else if(mode=="__DF__") // 64 bits result=double_type(); else if(mode=="__TF__") // 128 bits result=gcc_float128_type(); else if(mode=="__V2SF__") // vector of 2 floats, deprecated by gcc result=vector_typet(float_type(), from_integer(2, size_type())); else if(mode=="__V2DF__") // vector of 2 doubles, deprecated by gcc result=vector_typet(double_type(), from_integer(2, size_type())); else if(mode=="__V4SF__") // vector of 4 floats, deprecated by gcc result=vector_typet(float_type(), from_integer(4, size_type())); else if(mode=="__V4DF__") // vector of 4 doubles, deprecated by gcc result=vector_typet(double_type(), from_integer(4, size_type())); else // give up, just use subtype result=type.subtype(); // save the location result.add_source_location()=type.source_location(); type=result; } else if(underlying_type.id()==ID_complex) { // gcc allows this, but clang doesn't -- see enums above typet result; if(mode=="__SC__") // 32 bits result=float_type(); else if(mode=="__DC__") // 64 bits result=double_type(); else if(mode=="__TC__") // 128 bits result=gcc_float128_type(); else // give up, just use subtype result=type.subtype(); // save the location result.add_source_location()=type.source_location(); type=complex_typet(result); } else { error().source_location=type.source_location(); error() << "attribute mode `" << mode << "' applied to inappropriate type `" << to_string(type) << "'" << eom; throw 0; } } // do a mild bit of rule checking if(type.get_bool(ID_C_restricted) && type.id()!=ID_pointer && type.id()!=ID_array) { error().source_location=type.source_location(); error() << "only a pointer can be 'restrict'" << eom; throw 0; } }
bool simplify_exprt::simplify_index(exprt &expr) { bool result=true; // extra arithmetic optimizations const exprt &index=to_index_expr(expr).index(); const exprt &array=to_index_expr(expr).array(); if(index.id()==ID_div && index.operands().size()==2) { if(index.op0().id()==ID_mult && index.op0().operands().size()==2 && index.op0().op1()==index.op1()) { exprt tmp=index.op0().op0(); expr.op1()=tmp; result=false; } else if(index.op0().id()==ID_mult && index.op0().operands().size()==2 && index.op0().op0()==index.op1()) { exprt tmp=index.op0().op1(); expr.op1()=tmp; result=false; } } if(array.id()==ID_lambda) { // simplify (lambda i: e)(x) to e[i/x] const exprt &lambda_expr=array; if(lambda_expr.operands().size()!=2) return true; if(expr.op1().type()==lambda_expr.op0().type()) { exprt tmp=lambda_expr.op1(); replace_expr(lambda_expr.op0(), expr.op1(), tmp); expr.swap(tmp); return false; } } else if(array.id()==ID_with) { // we have (a WITH [i:=e])[j] const exprt &with_expr=array; if(with_expr.operands().size()!=3) return true; if(with_expr.op1()==expr.op1()) { // simplify (e with [i:=v])[i] to v exprt tmp=with_expr.op2(); expr.swap(tmp); return false; } else { // Turn (a with i:=x)[j] into (i==j)?x:a[j]. // watch out that the type of i and j might be different. equal_exprt equality_expr(expr.op1(), with_expr.op1()); if(equality_expr.lhs().type()!=equality_expr.rhs().type()) equality_expr.rhs().make_typecast(equality_expr.lhs().type()); simplify_inequality(equality_expr); index_exprt new_index_expr; new_index_expr.type()=expr.type(); new_index_expr.array()=with_expr.op0(); new_index_expr.index()=expr.op1(); simplify_index(new_index_expr); // recursive call if(equality_expr.is_true()) { expr=with_expr.op2(); return false; } else if(equality_expr.is_false()) { expr.swap(new_index_expr); return false; } if_exprt if_expr(equality_expr, with_expr.op2(), new_index_expr); simplify_if(if_expr); expr.swap(if_expr); return false; } } else if(array.id()==ID_constant || array.id()==ID_array) { mp_integer i; if(to_integer(expr.op1(), i)) { } else if(i<0 || i>=array.operands().size()) { // out of bounds } else { // ok exprt tmp=array.operands()[integer2size_t(i)]; expr.swap(tmp); return false; } } else if(array.id()==ID_string_constant) { mp_integer i; const irep_idt &value=array.get(ID_value); if(to_integer(expr.op1(), i)) { } else if(i<0 || i>value.size()) { // out of bounds } else { // terminating zero? char v=(i==value.size())?0:value[integer2size_t(i)]; exprt tmp=from_integer(v, expr.type()); expr.swap(tmp); return false; } } else if(array.id()==ID_array_of) { if(array.operands().size()==1) { exprt tmp=array.op0(); expr.swap(tmp); return false; } } else if(array.id()=="array-list") { // These are index/value pairs, alternating. for(size_t i=0; i<array.operands().size()/2; i++) { exprt tmp_index=array.operands()[i*2]; tmp_index.make_typecast(index.type()); simplify(tmp_index); if(tmp_index==index) { exprt tmp=array.operands()[i*2+1]; expr.swap(tmp); return false; } } } else if(array.id()==ID_byte_extract_little_endian || array.id()==ID_byte_extract_big_endian) { const typet &array_type=ns.follow(array.type()); if(array_type.id()==ID_array) { // This rewrites byte_extract(s, o, array_type)[i] // to byte_extract(s, o+offset, sub_type) mp_integer sub_size=pointer_offset_size(array_type.subtype(), ns); if(sub_size==-1) return true; // add offset to index mult_exprt offset(from_integer(sub_size, array.op1().type()), index); plus_exprt final_offset(array.op1(), offset); simplify_node(final_offset); exprt result(array.id(), expr.type()); result.copy_to_operands(array.op0(), final_offset); expr.swap(result); simplify_rec(expr); return false; } } else if(array.id()==ID_if) { const if_exprt &if_expr=to_if_expr(array); exprt cond=if_expr.cond(); index_exprt idx_false=to_index_expr(expr); idx_false.array()=if_expr.false_case(); to_index_expr(expr).array()=if_expr.true_case(); expr=if_exprt(cond, expr, idx_false, expr.type()); simplify_rec(expr); return false; } return result; }
codet cpp_typecheckt::cpp_constructor( const source_locationt &source_location, const exprt &object, const exprt::operandst &operands) { exprt object_tc=object; typecheck_expr(object_tc); elaborate_class_template(object_tc.type()); typet tmp_type(object_tc.type()); follow_symbol(tmp_type); assert(!is_reference(tmp_type)); if(tmp_type.id()==ID_array) { // We allow only one operand and it must be tagged with '#array_ini'. // Note that the operand is an array that is used for copy-initialization. // In the general case, a program is not allow to use this form of // construct. This way of initializing an array is used internaly only. // The purpose of the tag #arra_ini is to rule out ill-formed // programs. if(!operands.empty() && !operands.front().get_bool("#array_ini")) { error().source_location=source_location; error() << "bad array initializer" << eom; throw 0; } assert(operands.empty() || operands.size()==1); if(operands.empty() && cpp_is_pod(tmp_type)) { codet nil; nil.make_nil(); return nil; } const exprt &size_expr= to_array_type(tmp_type).size(); if(size_expr.id()=="infinity") { // don't initialize codet nil; nil.make_nil(); return nil; } exprt tmp_size=size_expr; make_constant_index(tmp_size); mp_integer s; if(to_integer(tmp_size, s)) { error().source_location=source_location; error() << "array size `" << to_string(size_expr) << "' is not a constant" << eom; throw 0; } /*if(cpp_is_pod(tmp_type)) { code_expressiont new_code; exprt op_tc=operands.front(); typecheck_expr(op_tc); // Override constantness object_tc.type().set("#constant", false); object_tc.set("#lvalue", true); side_effect_exprt assign("assign"); assign.add_source_location()=source_location; assign.copy_to_operands(object_tc, op_tc); typecheck_side_effect_assignment(assign); new_code.expression()=assign; return new_code; } else*/ { codet new_code(ID_block); // for each element of the array, call the default constructor for(mp_integer i=0; i < s; ++i) { exprt::operandst tmp_operands; exprt constant=from_integer(i, index_type()); constant.add_source_location()=source_location; exprt index(ID_index); index.copy_to_operands(object); index.copy_to_operands(constant); index.add_source_location()=source_location; if(!operands.empty()) { exprt operand(ID_index); operand.copy_to_operands(operands.front()); operand.copy_to_operands(constant); operand.add_source_location()=source_location; tmp_operands.push_back(operand); } exprt i_code = cpp_constructor(source_location, index, tmp_operands); if(i_code.is_nil()) { new_code.is_nil(); break; } new_code.move_to_operands(i_code); } return new_code; } } else if(cpp_is_pod(tmp_type)) { code_expressiont new_code; exprt::operandst operands_tc=operands; for(exprt::operandst::iterator it=operands_tc.begin(); it!=operands_tc.end(); it++) { typecheck_expr(*it); add_implicit_dereference(*it); } if(operands_tc.empty()) { // a POD is NOT initialized new_code.make_nil(); } else if(operands_tc.size()==1) { // Override constantness object_tc.type().set(ID_C_constant, false); object_tc.set(ID_C_lvalue, true); side_effect_exprt assign(ID_assign); assign.add_source_location()=source_location; assign.copy_to_operands(object_tc, operands_tc.front()); typecheck_side_effect_assignment(assign); new_code.expression()=assign; } else { error().source_location=source_location; error() << "initialization of POD requires one argument, " "but got " << operands.size() << eom; throw 0; } return new_code; } else if(tmp_type.id()==ID_union) { assert(0); // Todo: union } else if(tmp_type.id()==ID_struct) { exprt::operandst operands_tc=operands; for(exprt::operandst::iterator it=operands_tc.begin(); it!=operands_tc.end(); it++) { typecheck_expr(*it); add_implicit_dereference(*it); } const struct_typet &struct_type= to_struct_type(tmp_type); // set most-derived bits codet block(ID_block); for(std::size_t i=0; i < struct_type.components().size(); i++) { const irept &component=struct_type.components()[i]; if(component.get(ID_base_name)!="@most_derived") continue; exprt member(ID_member, bool_typet()); member.set(ID_component_name, component.get(ID_name)); member.copy_to_operands(object_tc); member.add_source_location()=source_location; member.set(ID_C_lvalue, object_tc.get_bool(ID_C_lvalue)); exprt val=false_exprt(); if(!component.get_bool("from_base")) val=true_exprt(); side_effect_exprt assign(ID_assign); assign.add_source_location()=source_location; assign.move_to_operands(member, val); typecheck_side_effect_assignment(assign); code_expressiont code_exp; code_exp.expression()=assign; block.move_to_operands(code_exp); } // enter struct scope cpp_save_scopet save_scope(cpp_scopes); cpp_scopes.set_scope(struct_type.get(ID_name)); // find name of constructor const struct_typet::componentst &components= struct_type.components(); irep_idt constructor_name; for(struct_typet::componentst::const_iterator it=components.begin(); it!=components.end(); it++) { const typet &type=it->type(); if(!it->get_bool(ID_from_base) && type.id()==ID_code && type.find(ID_return_type).id()==ID_constructor) { constructor_name=it->get(ID_base_name); break; } } // there is always a constructor for non-PODs assert(constructor_name!=""); irept cpp_name(ID_cpp_name); cpp_name.get_sub().push_back(irept(ID_name)); cpp_name.get_sub().back().set(ID_identifier, constructor_name); cpp_name.get_sub().back().set(ID_C_source_location, source_location); side_effect_expr_function_callt function_call; function_call.add_source_location()=source_location; function_call.function().swap(static_cast<exprt&>(cpp_name)); function_call.arguments().reserve(operands_tc.size()); for(exprt::operandst::iterator it=operands_tc.begin(); it!=operands_tc.end(); it++) function_call.op1().copy_to_operands(*it); typecheck_side_effect_function_call(function_call); assert(function_call.get(ID_statement)==ID_temporary_object); exprt &initializer = static_cast<exprt &>(function_call.add(ID_initializer)); assert(initializer.id()==ID_code && initializer.get(ID_statement)==ID_expression); side_effect_expr_function_callt &func_ini= to_side_effect_expr_function_call(initializer.op0()); exprt &tmp_this=func_ini.arguments().front(); assert(tmp_this.id()==ID_address_of && tmp_this.op0().id()=="new_object"); exprt address_of(ID_address_of, typet(ID_pointer)); address_of.type().subtype()=object_tc.type(); address_of.copy_to_operands(object_tc); tmp_this.swap(address_of); if(block.operands().empty()) return to_code(initializer); else { block.move_to_operands(initializer); return block; } } else assert(false); codet nil; nil.make_nil(); return nil; }
void goto_symext::symex_other( const goto_functionst &goto_functions, statet &state) { const goto_programt::instructiont &instruction=*state.source.pc; const codet &code=to_code(instruction.code); const irep_idt &statement=code.get_statement(); if(statement==ID_expression) { // ignore } else if(statement==ID_cpp_delete || statement=="cpp_delete[]") { codet clean_code=code; clean_expr(clean_code, state, false); symex_cpp_delete(state, clean_code); } else if(statement==ID_free) { // ignore } else if(statement==ID_printf) { codet clean_code=code; clean_expr(clean_code, state, false); symex_printf(state, nil_exprt(), clean_code); } else if(statement==ID_input) { codet clean_code(code); clean_expr(clean_code, state, false); symex_input(state, clean_code); } else if(statement==ID_output) { codet clean_code(code); clean_expr(clean_code, state, false); symex_output(state, clean_code); } else if(statement==ID_decl) { assert(false); // see symex_decl.cpp } else if(statement==ID_nondet) { // like skip } else if(statement==ID_asm) { // we ignore this for now } else if(statement==ID_array_copy) { assert(code.operands().size()==2); codet clean_code(code); // we need to add dereferencing for both operands dereference_exprt d0, d1; d0.op0()=code.op0(); d0.type()=code.op0().type().subtype(); d1.op0()=code.op1(); d1.type()=code.op1().type().subtype(); clean_code.op0()=d0; clean_code.op1()=d1; clean_expr(clean_code.op0(), state, true); clean_expr(clean_code.op1(), state, false); process_array_expr(clean_code.op0()); clean_expr(clean_code.op0(), state, true); process_array_expr(clean_code.op1()); clean_expr(clean_code.op1(), state, false); if(!base_type_eq(clean_code.op0().type(), clean_code.op1().type(), ns)) { byte_extract_exprt be(byte_extract_id()); be.type()=clean_code.op0().type(); be.op()=clean_code.op1(); be.offset()=from_integer(0, index_type()); clean_code.op1()=be; } code_assignt assignment; assignment.lhs()=clean_code.op0(); assignment.rhs()=clean_code.op1(); symex_assign(state, assignment); } else if(statement==ID_array_set) { assert(code.operands().size()==2); codet clean_code(code); // we need to add dereferencing for the first operand dereference_exprt d0; d0.op0()=code.op0(); d0.type()=code.op0().type().subtype(); clean_code.op0()=d0; clean_expr(clean_code.op0(), state, true); clean_expr(clean_code.op1(), state, false); process_array_expr(clean_code.op0()); clean_expr(clean_code.op0(), state, true); const typet &op0_type=ns.follow(clean_code.op0().type()); if(op0_type.id()!=ID_array) throw "array_set expects array operand"; const array_typet &array_type= to_array_type(op0_type); if(!base_type_eq(array_type.subtype(), clean_code.op1().type(), ns)) clean_code.op1().make_typecast(array_type.subtype()); code_assignt assignment; assignment.lhs()=clean_code.op0(); assignment.rhs()=array_of_exprt(clean_code.op1(), array_type); symex_assign(state, assignment); } else if(statement==ID_user_specified_predicate || statement==ID_user_specified_parameter_predicates || statement==ID_user_specified_return_predicates) { // like skip } else if(statement==ID_fence) { target.memory_barrier(state.guard.as_expr(), state.source); } else throw "unexpected statement: "+id2string(statement); }
void c_typecheck_baset::add_argc_argv(const symbolt &main_symbol) { const irept &arguments=main_symbol.type.arguments(); if(arguments.get_sub().size()==0) return; if(arguments.get_sub().size()!=2 && arguments.get_sub().size()!=3) { err_location(main_symbol.location); throw "main expected to have no or two or three arguments"; } symbolt *argc_new_symbol; const exprt &op0=(exprt &)arguments.get_sub()[0]; const exprt &op1=(exprt &)arguments.get_sub()[1]; { symbolt argc_symbol; argc_symbol.base_name="argc"; argc_symbol.name="c::argc'"; argc_symbol.type=op0.type(); argc_symbol.static_lifetime=true; argc_symbol.lvalue=true; if(argc_symbol.type.id()!="signedbv" && argc_symbol.type.id()!="unsignedbv") { err_location(main_symbol.location); str << "argc argument expected to be integer type, but got `" << to_string(argc_symbol.type) << "'"; throw 0; } move_symbol(argc_symbol, argc_new_symbol); } { if(op1.type().id()!="pointer" || op1.type().subtype().id()!="pointer") { err_location(main_symbol.location); str << "argv argument expected to be pointer-to-pointer type, " "but got `" << to_string(op1.type()) << "'"; throw 0; } // we make the type of this thing an array of pointers typet argv_type=array_typet(); argv_type.subtype()=op1.type().subtype(); // need to add one to the size -- the array is terminated // with NULL exprt one_expr=from_integer(1, argc_new_symbol->type); exprt size_expr("+", argc_new_symbol->type); size_expr.copy_to_operands(symbol_expr(*argc_new_symbol), one_expr); argv_type.size(size_expr); symbolt argv_symbol; argv_symbol.base_name="argv"; argv_symbol.name="c::argv'"; argv_symbol.type=argv_type; argv_symbol.static_lifetime=true; argv_symbol.lvalue=true; symbolt *argv_new_symbol; move_symbol(argv_symbol, argv_new_symbol); } if (arguments.get_sub().size()==3) { symbolt envp_symbol; envp_symbol.base_name="envp"; envp_symbol.name="c::envp'"; envp_symbol.type=(static_cast<const exprt&>(arguments.get_sub()[2])).type(); envp_symbol.static_lifetime=true; symbolt envp_size_symbol, *envp_new_size_symbol; envp_size_symbol.base_name="envp_size"; envp_size_symbol.name="c::envp_size'"; envp_size_symbol.type=op0.type(); // same type as argc! envp_size_symbol.static_lifetime=true; move_symbol(envp_size_symbol, envp_new_size_symbol); if(envp_symbol.type.id()!="pointer") { err_location(main_symbol.location); str << "envp argument expected to be pointer type, but got `" << to_string(envp_symbol.type) << "'"; throw 0; } exprt size_expr = symbol_expr(*envp_new_size_symbol); envp_symbol.type.id("array"); envp_symbol.type.size(size_expr); symbolt *envp_new_symbol; move_symbol(envp_symbol, envp_new_symbol); } }
bool simplify_exprt::simplify_address_of_arg(exprt &expr) { if(expr.id()==ID_index) { if(expr.operands().size()==2) { bool result=true; if(!simplify_address_of_arg(expr.op0())) result=false; if(!simplify_rec(expr.op1())) result=false; // rewrite (*(type *)int) [index] by // pushing the index inside mp_integer address; if(is_dereference_integer_object(expr.op0(), address)) { // push index into address mp_integer step_size, index; step_size=pointer_offset_size(expr.type(), ns); if(!to_integer(expr.op1(), index) && step_size!=-1) { unsignedbv_typet int_type(config.ansi_c.pointer_width); pointer_typet pointer_type; pointer_type.subtype()=expr.type(); typecast_exprt typecast_expr( from_integer(step_size*index+address, int_type), pointer_type); exprt new_expr=dereference_exprt(typecast_expr, expr.type()); expr=new_expr; result=true; } } return result; } } else if(expr.id()==ID_member) { if(expr.operands().size()==1) { bool result=true; if(!simplify_address_of_arg(expr.op0())) result=false; const typet &op_type=ns.follow(expr.op0().type()); if(op_type.id()==ID_struct) { // rewrite NULL -> member by // pushing the member inside mp_integer address; if(is_dereference_integer_object(expr.op0(), address)) { const struct_typet &struct_type=to_struct_type(op_type); const irep_idt &member=to_member_expr(expr).get_component_name(); mp_integer offset=member_offset(struct_type, member, ns); if(offset!=-1) { unsignedbv_typet int_type(config.ansi_c.pointer_width); pointer_typet pointer_type; pointer_type.subtype()=expr.type(); typecast_exprt typecast_expr( from_integer(address+offset, int_type), pointer_type); exprt new_expr=dereference_exprt(typecast_expr, expr.type()); expr=new_expr; result=true; } } } return result; } } else if(expr.id()==ID_dereference) { if(expr.operands().size()==1) return simplify_rec(expr.op0()); } else if(expr.id()==ID_if) { if(expr.operands().size()==3) { bool result=true; if(!simplify_rec(expr.op0())) result=false; if(!simplify_address_of_arg(expr.op1())) result=false; if(!simplify_address_of_arg(expr.op2())) result=false; // op0 is a constant? if(expr.op0().is_true()) { result=false; exprt tmp; tmp.swap(expr.op1()); expr.swap(tmp); } else if(expr.op0().is_false()) { result=false; exprt tmp; tmp.swap(expr.op2()); expr.swap(tmp); } return result; } } return true; }
bool simplify_exprt::simplify_pointer_offset(exprt &expr) { if(expr.operands().size()!=1) return true; exprt &ptr=expr.op0(); if(ptr.id()==ID_if && ptr.operands().size()==3) { if_exprt if_expr=lift_if(expr, 0); simplify_pointer_offset(if_expr.true_case()); simplify_pointer_offset(if_expr.false_case()); simplify_if(if_expr); expr.swap(if_expr); return false; } if(ptr.type().id()!=ID_pointer) return true; if(ptr.id()==ID_address_of) { if(ptr.operands().size()!=1) return true; mp_integer offset=compute_pointer_offset(ptr.op0(), ns); if(offset!=-1) { expr=from_integer(offset, expr.type()); return false; } } else if(ptr.id()==ID_typecast) // pointer typecast { if(ptr.operands().size()!=1) return true; const typet &op_type=ns.follow(ptr.op0().type()); if(op_type.id()==ID_pointer) { // Cast from pointer to pointer. // This just passes through, remove typecast. exprt tmp=ptr.op0(); ptr=tmp; // recursive call simplify_node(expr); return false; } else if(op_type.id()==ID_signedbv || op_type.id()==ID_unsignedbv) { // Cast from integer to pointer, say (int *)x. if(ptr.op0().is_constant()) { // (T *)0x1234 -> 0x1234 exprt tmp=ptr.op0(); tmp.make_typecast(expr.type()); simplify_node(tmp); expr.swap(tmp); return false; } else { // We do a bit of special treatment for (TYPE *)(a+(int)&o), // which is re-written to 'a'. typet type=ns.follow(expr.type()); exprt tmp=ptr.op0(); if(tmp.id()==ID_plus && tmp.operands().size()==2) { if(tmp.op0().id()==ID_typecast && tmp.op0().operands().size()==1 && tmp.op0().op0().id()==ID_address_of) { expr=tmp.op1(); if(type!=expr.type()) expr.make_typecast(type); simplify_node(expr); return false; } else if(tmp.op1().id()==ID_typecast && tmp.op1().operands().size()==1 && tmp.op1().op0().id()==ID_address_of) { expr=tmp.op0(); if(type!=expr.type()) expr.make_typecast(type); simplify_node(expr); return false; } } } } } else if(ptr.id()==ID_plus) // pointer arithmetic { exprt::operandst ptr_expr; exprt::operandst int_expr; for(const auto & op : ptr.operands()) { if(op.type().id()==ID_pointer) ptr_expr.push_back(op); else if(!op.is_zero()) { exprt tmp=op; if(tmp.type()!=expr.type()) { tmp.make_typecast(expr.type()); simplify_node(tmp); } int_expr.push_back(tmp); } } if(ptr_expr.size()!=1 || int_expr.empty()) return true; typet pointer_type=ptr_expr.front().type(); mp_integer element_size= pointer_offset_size(pointer_type.subtype(), ns); if(element_size==0) return true; // this might change the type of the pointer! exprt pointer_offset(ID_pointer_offset, expr.type()); pointer_offset.copy_to_operands(ptr_expr.front()); simplify_node(pointer_offset); exprt sum; if(int_expr.size()==1) sum=int_expr.front(); else { sum=exprt(ID_plus, expr.type()); sum.operands()=int_expr; } simplify_node(sum); exprt size_expr= from_integer(element_size, expr.type()); binary_exprt product(sum, ID_mult, size_expr, expr.type()); simplify_node(product); expr=binary_exprt(pointer_offset, ID_plus, product, expr.type()); simplify_node(expr); return false; } else if(ptr.id()==ID_constant && ptr.get(ID_value)==ID_NULL) { expr=gen_zero(expr.type()); simplify_node(expr); return false; } return true; }
void java_bytecode_parsert::rbytecode( methodt::instructionst &instructions) { u4 code_length=read_u4(); u4 address; size_t bytecode_index=0; // index of bytecode instruction for(address=0; address<code_length; address++) { bool wide_instruction=false; u4 start_of_instruction=address; u1 bytecode=read_u1(); if(bytecode==0xc4) // wide { wide_instruction=true; address++; bytecode=read_u1(); } instructions.push_back(instructiont()); instructiont &instruction=instructions.back(); instruction.statement=bytecodes[bytecode].mnemonic; instruction.address=start_of_instruction; instruction.source_location .set_java_bytecode_index(std::to_string(bytecode_index)); switch(bytecodes[bytecode].format) { case ' ': // no further bytes break; case 'c': // a constant_pool index (one byte) if(wide_instruction) { instruction.args.push_back(constant(read_u2())); address+=2; } else { instruction.args.push_back(constant(read_u1())); address+=1; } break; case 'C': // a constant_pool index (two bytes) instruction.args.push_back(constant(read_u2())); address+=2; break; case 'b': // a signed byte { s1 c=read_u1(); instruction.args.push_back(from_integer(c, integer_typet())); } address+=1; break; case 'o': // two byte branch offset, signed { s2 offset=read_u2(); instruction .args.push_back(from_integer(address+offset, integer_typet())); } address+=2; break; case 'O': // four byte branch offset, signed { s4 offset=read_u4(); instruction .args.push_back(from_integer(address+offset, integer_typet())); } address+=4; break; case 'v': // local variable index (one byte) { u1 v=read_u1(); instruction.args.push_back(from_integer(v, integer_typet())); } address+=1; break; case 'V': // local variable index (two bytes) plus two signed bytes if(wide_instruction) { u2 v=read_u2(); instruction.args.push_back(from_integer(v, integer_typet())); s2 c=read_u2(); instruction.args.push_back(from_integer(c, integer_typet())); address+=4; } else // local variable index (one byte) plus one signed byte { u1 v=read_u1(); instruction.args.push_back(from_integer(v, integer_typet())); s1 c=read_u1(); instruction.args.push_back(from_integer(c, integer_typet())); address+=2; } break; case 'I': // two byte constant_pool index plus two bytes { u2 c=read_u2(); instruction.args.push_back(constant(c)); u1 b1=read_u1(); instruction.args.push_back(from_integer(b1, integer_typet())); u1 b2=read_u1(); instruction.args.push_back(from_integer(b2, integer_typet())); } address+=4; break; case 'L': // lookupswitch { u4 base_offset=address; // first a pad to 32-bit align while(((address+1)&3)!=0) { read_u1(); address++; } // now default value s4 default_value=read_u4(); instruction.args .push_back(from_integer(base_offset+default_value, integer_typet())); address+=4; // number of pairs u4 npairs=read_u4(); address+=4; for(std::size_t i=0; i<npairs; i++) { s4 match=read_u4(); s4 offset=read_u4(); instruction.args.push_back(from_integer(match, integer_typet())); instruction.args .push_back(from_integer(base_offset+offset, integer_typet())); address+=8; } } break; case 'T': // tableswitch { size_t base_offset=address; // first a pad to 32-bit align while(((address+1)&3)!=0) { read_u1(); address++; } // now default value s4 default_value=read_u4(); instruction.args .push_back(from_integer(base_offset+default_value, integer_typet())); address+=4; // now low value s4 low_value=read_u4(); address+=4; // now high value s4 high_value=read_u4(); address+=4; // there are high-low+1 offsets, and they are signed for(s4 i=low_value; i<=high_value; i++) { s4 offset=read_u4(); instruction.args.push_back(from_integer(i, integer_typet())); instruction.args .push_back(from_integer(base_offset+offset, integer_typet())); address+=4; } } break; case 'm': // multianewarray: constant-pool index plus one unsigned byte { u2 c=read_u2(); // constant-pool index instruction.args.push_back(constant(c)); u1 dimensions=read_u1(); // number of dimensions instruction.args.push_back(from_integer(dimensions, integer_typet())); address+=3; } break; case 't': // array subtype, one byte { typet t; switch(read_u1()) { case T_BOOLEAN: t.id(ID_bool); break; case T_CHAR: t.id(ID_char); break; case T_FLOAT: t.id(ID_float); break; case T_DOUBLE: t.id(ID_double); break; case T_BYTE: t.id(ID_byte); break; case T_SHORT: t.id(ID_short); break; case T_INT: t.id(ID_int); break; case T_LONG: t.id(ID_long); break; default:{}; } instruction.args.push_back(type_exprt(t)); } address+=1; break; case 's': // a signed short { s2 s=read_u2(); instruction.args.push_back(from_integer(s, integer_typet())); } address+=2; break; default: throw "unknown JVM bytecode instruction"; } bytecode_index++; } if(address!=code_length) { error() << "bytecode length mismatch" << eom; throw 0; } }
void polynomial_acceleratort::assert_for_values(scratch_programt &program, std::map<exprt, int> &values, std::set<std::pair<expr_listt, exprt> > &coefficients, int num_unwindings, goto_programt::instructionst &loop_body, exprt &target, overflow_instrumentert &overflow) { // First figure out what the appropriate type for this expression is. typet expr_type = nil_typet(); for (std::map<exprt, int>::iterator it = values.begin(); it != values.end(); ++it) { typet this_type=it->first.type(); if (this_type.id() == ID_pointer) { #ifdef DEBUG std::cout << "Overriding pointer type" << std::endl; #endif this_type = unsignedbv_typet(config.ansi_c.pointer_width); } if (expr_type == nil_typet()) { expr_type = this_type; } else { expr_type = join_types(expr_type, this_type); } } assert(to_bitvector_type(expr_type).get_width()>0); // Now set the initial values of the all the variables... for (std::map<exprt, int>::iterator it = values.begin(); it != values.end(); ++it) { program.assign(it->first, from_integer(it->second, expr_type)); } // Now unwind the loop as many times as we need to. for (int i = 0; i < num_unwindings; i++) { program.append(loop_body); } // Now build the polynomial for this point and assert it fits. exprt rhs = nil_exprt(); for (std::set<std::pair<expr_listt, exprt> >::iterator it = coefficients.begin(); it != coefficients.end(); ++it) { int concrete_value = 1; for (expr_listt::const_iterator e_it = it->first.begin(); e_it != it->first.end(); ++e_it) { exprt e = *e_it; if (e == loop_counter) { concrete_value *= num_unwindings; } else { std::map<exprt, int>::iterator v_it = values.find(e); if (v_it != values.end()) { concrete_value *= v_it->second; } } } // OK, concrete_value now contains the value of all the relevant variables // multiplied together. Create the term concrete_value*coefficient and add // it into the polynomial. typecast_exprt cast(it->second, expr_type); exprt term = mult_exprt(from_integer(concrete_value, expr_type), cast); if (rhs.is_nil()) { rhs = term; } else { rhs = plus_exprt(rhs, term); } } exprt overflow_expr; overflow.overflow_expr(rhs, overflow_expr); program.add_instruction(ASSUME)->guard = not_exprt(overflow_expr); rhs = typecast_exprt(rhs, target.type()); // We now have the RHS of the polynomial. Assert that this is equal to the // actual value of the variable we're fitting. exprt polynomial_holds = equal_exprt(target, rhs); // Finally, assert that the polynomial equals the variable we're fitting. goto_programt::targett assumption = program.add_instruction(ASSUME); assumption->guard = polynomial_holds; }
void cpp_typecheckt::typecheck_enum_body(symbolt &enum_symbol) { c_enum_typet &c_enum_type=to_c_enum_type(enum_symbol.type); exprt &body=static_cast<exprt &>(c_enum_type.add(ID_body)); irept::subt &components=body.get_sub(); c_enum_tag_typet enum_tag_type(enum_symbol.name); mp_integer i=0; Forall_irep(it, components) { const irep_idt &name=it->get(ID_name); if(it->find(ID_value).is_not_nil()) { exprt &value=static_cast<exprt &>(it->add(ID_value)); typecheck_expr(value); implicit_typecast(value, c_enum_type.subtype()); make_constant(value); if(to_integer(value, i)) { error().source_location=value.find_source_location(); error() << "failed to produce integer for enum constant" << eom; throw 0; } } exprt value_expr=from_integer(i, c_enum_type.subtype()); value_expr.type()=enum_tag_type; // override type symbolt symbol; symbol.name=id2string(enum_symbol.name)+"::"+id2string(name); symbol.base_name=name; symbol.value=value_expr; symbol.location=static_cast<const source_locationt &>(it->find(ID_C_source_location)); symbol.mode=ID_cpp; symbol.module=module; symbol.type=enum_tag_type; symbol.is_type=false; symbol.is_macro=true; symbolt *new_symbol; if(symbol_table.move(symbol, new_symbol)) { error().source_location=symbol.location; error() << "cpp_typecheckt::typecheck_enum_body: symbol_table.move() failed" << eom; throw 0; } cpp_idt &scope_identifier= cpp_scopes.put_into_scope(*new_symbol); scope_identifier.id_class=cpp_idt::SYMBOL; ++i; } }
bool polynomial_acceleratort::check_inductive( std::map<exprt, polynomialt> polynomials, goto_programt::instructionst &body) { // Checking that our polynomial is inductive with respect to the loop body is // equivalent to checking safety of the following program: // // assume (target1 == polynomial1); // assume (target2 == polynomial2) // ... // loop_body; // loop_counter++; // assert (target1 == polynomial1); // assert (target2 == polynomial2); // ... scratch_programt program(symbol_table); std::vector<exprt> polynomials_hold; substitutiont substitution; stash_polynomials(program, polynomials, substitution, body); for (std::map<exprt, polynomialt>::iterator it = polynomials.begin(); it != polynomials.end(); ++it) { exprt holds = equal_exprt(it->first, it->second.to_expr()); program.add_instruction(ASSUME)->guard = holds; polynomials_hold.push_back(holds); } program.append(body); codet inc_loop_counter = code_assignt(loop_counter, plus_exprt(loop_counter, from_integer(1, loop_counter.type()))); program.add_instruction(ASSIGN)->code = inc_loop_counter; for (std::vector<exprt>::iterator it = polynomials_hold.begin(); it != polynomials_hold.end(); ++it) { program.add_instruction(ASSERT)->guard = *it; } #ifdef DEBUG std::cout << "Checking following program for inductiveness:" << std::endl; program.output(ns, "", std::cout); #endif try { if (program.check_sat()) { // We found a counterexample to inductiveness... :-( #ifdef DEBUG std::cout << "Not inductive!" << std::endl; #endif return false; } else { return true; } } catch (std::string s) { std::cout << "Error in inductiveness SAT check: " << s << std::endl; return false; } catch (const char *s) { std::cout << "Error in inductiveness SAT check: " << s << std::endl; return false; } }
void cvc_convt::convert_address_of_rec(const exprt &expr) { if(expr.id()==ID_symbol || expr.id()==ID_constant || expr.id()==ID_string_constant) { out << "(# object:=" << pointer_logic.add_object(expr) << ", offset:=" << bin_zero(config.ansi_c.pointer_width) << " #)"; } else if(expr.id()==ID_index) { if(expr.operands().size()!=2) throw "index takes two operands"; const exprt &array=expr.op0(); const exprt &index=expr.op1(); if(index.is_zero()) { if(array.type().id()==ID_pointer) convert_expr(array); else if(array.type().id()==ID_array) convert_address_of_rec(array); else assert(false); } else { out << "(LET P: "; out << cvc_pointer_type(); out << " = "; if(array.type().id()==ID_pointer) convert_expr(array); else if(array.type().id()==ID_array) convert_address_of_rec(array); else assert(false); out << " IN P WITH .offset:=BVPLUS(" << config.ansi_c.pointer_width << ", P.offset, "; convert_expr(index); out << "))"; } } else if(expr.id()==ID_member) { if(expr.operands().size()!=1) throw "member takes one operand"; const exprt &struct_op=expr.op0(); out << "(LET P: "; out << cvc_pointer_type(); out << " = "; convert_address_of_rec(struct_op); const irep_idt &component_name= to_member_expr(expr).get_component_name(); mp_integer offset=member_offset( to_struct_type(struct_op.type()), component_name, ns); typet index_type(ID_unsignedbv); index_type.set(ID_width, config.ansi_c.pointer_width); exprt index=from_integer(offset, index_type); out << " IN P WITH .offset:=BVPLUS(" << config.ansi_c.pointer_width << ", P.offset, "; convert_expr(index); out << "))"; } else throw "don't know how to take address of: "+expr.id_string(); }
void c_typecheck_baset::typecheck_c_enum_type(typet &type) { // These come with the declarations // of the enum constants as operands. exprt &as_expr=static_cast<exprt &>(static_cast<irept &>(type)); source_locationt source_location=type.source_location(); // We allow empty enums in the grammar to get better // error messages. if(as_expr.operands().empty()) { error().source_location=source_location; error() << "empty enum" << eom; throw 0; } // enums start at zero; // we also track min and max to find a nice base type mp_integer value=0, min_value=0, max_value=0; std::list<c_enum_typet::c_enum_membert> enum_members; // We need to determine a width, and a signedness // to obtain an 'underlying type'. // We just do int, but gcc might pick smaller widths // if the type is marked as 'packed'. // gcc/clang may also pick a larger width. Visual Studio doesn't. for(auto &op : as_expr.operands()) { ansi_c_declarationt &declaration=to_ansi_c_declaration(op); exprt &v=declaration.declarator().value(); if(v.is_not_nil()) // value given? { exprt tmp_v=v; typecheck_expr(tmp_v); add_rounding_mode(tmp_v); simplify(tmp_v, *this); if(tmp_v.is_true()) value=1; else if(tmp_v.is_false()) value=0; else if(!to_integer(tmp_v, value)) { } else { error().source_location=v.source_location(); error() << "enum is not a constant"; throw 0; } } if(value<min_value) min_value=value; if(value>max_value) max_value=value; typet constant_type= enum_constant_type(min_value, max_value); v=from_integer(value, constant_type); declaration.type()=constant_type; typecheck_declaration(declaration); irep_idt base_name= declaration.declarator().get_base_name(); irep_idt identifier= declaration.declarator().get_name(); // store c_enum_typet::c_enum_membert member; member.set_identifier(identifier); member.set_base_name(base_name); member.set_value(integer2string(value)); enum_members.push_back(member); // produce value for next constant ++value; } // Remove these now; we add them to the // c_enum symbol later. as_expr.operands().clear(); bool is_packed=type.get_bool(ID_C_packed); // tag? if(type.find(ID_tag).is_nil()) { // None, it's anonymous. We generate a tag. std::string anon_identifier="#anon_enum"; for(const auto &member : enum_members) { anon_identifier+='$'; anon_identifier+=id2string(member.get_base_name()); anon_identifier+='='; anon_identifier+=id2string(member.get_value()); } if(is_packed) anon_identifier+="#packed"; type.add(ID_tag).set(ID_identifier, anon_identifier); } irept &tag=type.add(ID_tag); irep_idt base_name=tag.get(ID_C_base_name); irep_idt identifier=tag.get(ID_identifier); // Put into symbol table symbolt enum_tag_symbol; enum_tag_symbol.is_type=true; enum_tag_symbol.type=type; enum_tag_symbol.location=source_location; enum_tag_symbol.is_file_local=true; enum_tag_symbol.base_name=base_name; enum_tag_symbol.name=identifier; // throw in the enum members as 'body' irept::subt &body=enum_tag_symbol.type.add(ID_body).get_sub(); for(const auto &member : enum_members) body.push_back(member); // We use a subtype to store the underlying type. typet underlying_type= enum_underlying_type(min_value, max_value, is_packed); enum_tag_symbol.type.subtype()=underlying_type; // is it in the symbol table already? symbol_tablet::symbolst::iterator s_it= symbol_table.symbols.find(identifier); if(s_it!=symbol_table.symbols.end()) { // Yes. symbolt &symbol=s_it->second; if(symbol.type.id()==ID_incomplete_c_enum) { // Ok, overwrite the type in the symbol table. // This gives us the members and the subtype. symbol.type=enum_tag_symbol.type; } else if(symbol.type.id()==ID_c_enum) { // We might already have the same anonymous enum, and this is // simply ok. Note that the C standard treats these as // different types. if(!base_name.empty()) { error().source_location=type.source_location(); error() << "redeclaration of enum tag" << eom; throw 0; } } else { error().source_location=source_location; error() << "use of tag that does not match previous declaration" << eom; throw 0; } } else { symbolt *new_symbol; move_symbol(enum_tag_symbol, new_symbol); } // We produce a c_enum_tag as the resulting type. type.id(ID_c_enum_tag); type.remove(ID_tag); type.set(ID_identifier, identifier); }
exprt interval_domaint::make_expression(const symbol_exprt &src) const { if(is_int(src.type())) { int_mapt::const_iterator i_it=int_map.find(src.get_identifier()); if(i_it==int_map.end()) return true_exprt(); const integer_intervalt &interval=i_it->second; if(interval.is_top()) return true_exprt(); if(interval.is_bottom()) return false_exprt(); exprt::operandst conjuncts; if(interval.upper_set) { exprt tmp=from_integer(interval.upper, src.type()); conjuncts.push_back(binary_relation_exprt(src, ID_le, tmp)); } if(interval.lower_set) { exprt tmp=from_integer(interval.lower, src.type()); conjuncts.push_back(binary_relation_exprt(tmp, ID_le, src)); } return conjunction(conjuncts); } else if(is_float(src.type())) { float_mapt::const_iterator i_it=float_map.find(src.get_identifier()); if(i_it==float_map.end()) return true_exprt(); const ieee_float_intervalt &interval=i_it->second; if(interval.is_top()) return true_exprt(); if(interval.is_bottom()) return false_exprt(); exprt::operandst conjuncts; if(interval.upper_set) { exprt tmp=interval.upper.to_expr(); conjuncts.push_back(binary_relation_exprt(src, ID_le, tmp)); } if(interval.lower_set) { exprt tmp=interval.lower.to_expr(); conjuncts.push_back(binary_relation_exprt(tmp, ID_le, src)); } return conjunction(conjuncts); } else return true_exprt(); }
void c_typecheck_baset::typecheck_vector_type(vector_typet &type) { exprt &size=type.size(); source_locationt source_location=size.find_source_location(); typecheck_expr(size); typet &subtype=type.subtype(); typecheck_type(subtype); // we are willing to combine 'vector' with various // other types, but not everything! if(subtype.id()!=ID_signedbv && subtype.id()!=ID_unsignedbv && subtype.id()!=ID_floatbv && subtype.id()!=ID_fixedbv) { error().source_location=source_location; error() << "cannot make a vector of subtype " << to_string(subtype) << eom; throw 0; } make_constant_index(size); mp_integer s; if(to_integer(size, s)) { error().source_location=source_location; error() << "failed to convert constant: " << size.pretty() << eom; throw 0; } if(s<=0) { error().source_location=source_location; error() << "vector size must be positive, " "but got " << s << eom; throw 0; } // the subtype must have constant size exprt size_expr=c_sizeof(type.subtype(), *this); simplify(size_expr, *this); mp_integer sub_size; if(to_integer(size_expr, sub_size)) { error().source_location=source_location; error() << "failed to determine size of vector base type `" << to_string(type.subtype()) << "'" << eom; throw 0; } if(sub_size==0) { error().source_location=source_location; error() << "type had size 0: `" << to_string(type.subtype()) << "'" << eom; throw 0; } // adjust by width of base type if(s%sub_size!=0) { error().source_location=source_location; error() << "vector size (" << s << ") expected to be multiple of base type size (" << sub_size << ")" << eom; throw 0; } s/=sub_size; type.size()=from_integer(s, signed_size_type()); }
void c_typecheck_baset::add_argc_argv(const symbolt &main_symbol) { const code_typet::parameterst ¶meters= to_code_type(main_symbol.type).parameters(); if(parameters.empty()) return; if(parameters.size()!=2 && parameters.size()!=3) { err_location(main_symbol.location); throw "main expected to have no or two or three parameters"; } symbolt *argc_new_symbol; const exprt &op0=static_cast<const exprt &>(parameters[0]); const exprt &op1=static_cast<const exprt &>(parameters[1]); { symbolt argc_symbol; argc_symbol.base_name="argc"; argc_symbol.name="argc'"; argc_symbol.type=op0.type(); argc_symbol.is_static_lifetime=true; argc_symbol.is_lvalue=true; if(argc_symbol.type.id()!=ID_signedbv && argc_symbol.type.id()!=ID_unsignedbv) { err_location(main_symbol.location); str << "argc argument expected to be integer type, but got `" << to_string(argc_symbol.type) << "'"; throw 0; } move_symbol(argc_symbol, argc_new_symbol); } { if(op1.type().id()!=ID_pointer || op1.type().subtype().id()!=ID_pointer) { err_location(main_symbol.location); str << "argv argument expected to be pointer-to-pointer type, " "but got `" << to_string(op1.type()) << "'"; throw 0; } // we make the type of this thing an array of pointers typet argv_type=array_typet(); argv_type.subtype()=op1.type().subtype(); // need to add one to the size -- the array is terminated // with NULL exprt one_expr=from_integer(1, argc_new_symbol->type); exprt size_expr(ID_plus, argc_new_symbol->type); size_expr.copy_to_operands(argc_new_symbol->symbol_expr(), one_expr); argv_type.add(ID_size).swap(size_expr); symbolt argv_symbol; argv_symbol.base_name="argv'"; argv_symbol.name="argv'"; argv_symbol.type=argv_type; argv_symbol.is_static_lifetime=true; argv_symbol.is_lvalue=true; symbolt *argv_new_symbol; move_symbol(argv_symbol, argv_new_symbol); } if(parameters.size()==3) { symbolt envp_symbol; envp_symbol.base_name="envp'"; envp_symbol.name="envp'"; envp_symbol.type=(static_cast<const exprt&>(parameters[2])).type(); envp_symbol.is_static_lifetime=true; symbolt envp_size_symbol, *envp_new_size_symbol; envp_size_symbol.base_name="envp_size"; envp_size_symbol.name="envp_size'"; envp_size_symbol.type=op0.type(); // same type as argc! envp_size_symbol.is_static_lifetime=true; move_symbol(envp_size_symbol, envp_new_size_symbol); if(envp_symbol.type.id()!=ID_pointer) { err_location(main_symbol.location); str << "envp argument expected to be pointer type, but got `" << to_string(envp_symbol.type) << "'"; throw 0; } exprt size_expr = envp_new_size_symbol->symbol_expr(); envp_symbol.type.id(ID_array); envp_symbol.type.add(ID_size).swap(size_expr); symbolt *envp_new_symbol; move_symbol(envp_symbol, envp_new_symbol); } }
bool simplify_exprt::simplify_floatbv_typecast(exprt &expr) { // These casts usually reduce precision, and thus, usually round. assert(expr.operands().size()==2); const typet &dest_type=ns.follow(expr.type()); const typet &src_type=ns.follow(expr.op0().type()); // eliminate redundant casts if(dest_type==src_type) { expr=expr.op0(); return false; } exprt op0=expr.op0(); exprt op1=expr.op1(); // rounding mode // We can soundly re-write (float)((double)x op (double)y) // to x op y. True for any rounding mode! #if 0 if(op0.id()==ID_floatbv_div || op0.id()==ID_floatbv_mult || op0.id()==ID_floatbv_plus || op0.id()==ID_floatbv_minus) { if(op0.operands().size()==3 && op0.op0().id()==ID_typecast && op0.op1().id()==ID_typecast && op0.op0().operands().size()==1 && op0.op1().operands().size()==1 && ns.follow(op0.op0().type())==dest_type && ns.follow(op0.op1().type())==dest_type) { exprt result(op0.id(), expr.type()); result.operands().resize(3); result.op0()=op0.op0().op0(); result.op1()=op0.op1().op0(); result.op2()=op1; simplify_node(result); expr.swap(result); return false; } } #endif // constant folding if(op0.is_constant() && op1.is_constant()) { mp_integer rounding_mode; if(!to_integer(op1, rounding_mode)) { if(src_type.id()==ID_floatbv) { if(dest_type.id()==ID_floatbv) // float to float { ieee_floatt result(to_constant_expr(op0)); result.rounding_mode= (ieee_floatt::rounding_modet)integer2size_t(rounding_mode); result.change_spec( ieee_float_spect(to_floatbv_type(dest_type))); expr=result.to_expr(); return false; } else if(dest_type.id()==ID_signedbv || dest_type.id()==ID_unsignedbv) { if(rounding_mode==ieee_floatt::ROUND_TO_ZERO) { ieee_floatt result(to_constant_expr(op0)); result.rounding_mode= (ieee_floatt::rounding_modet)integer2size_t(rounding_mode); mp_integer value=result.to_integer(); expr=from_integer(value, dest_type); return false; } } } else if(src_type.id()==ID_signedbv || src_type.id()==ID_unsignedbv) { mp_integer value; if(!to_integer(op0, value)) { if(dest_type.id()==ID_floatbv) // int to float { ieee_floatt result(to_floatbv_type(dest_type)); result.rounding_mode= (ieee_floatt::rounding_modet)integer2size_t(rounding_mode); result.from_integer(value); expr=result.to_expr(); return false; } } } } } #if 0 // (T)(a?b:c) --> a?(T)b:(T)c if(expr.op0().id()==ID_if && expr.op0().operands().size()==3) { exprt tmp_op1= binary_exprt( expr.op0().op1(), ID_floatbv_typecast, expr.op1(), dest_type); exprt tmp_op2= binary_exprt( expr.op0().op2(), ID_floatbv_typecast, expr.op1(), dest_type); simplify_floatbv_typecast(tmp_op1); simplify_floatbv_typecast(tmp_op2); expr=if_exprt(expr.op0().op0(), tmp_op1, tmp_op2, dest_type); simplify_if(expr); return false; } #endif return true; }
exprt dereferencet::read_object( const exprt &object, const exprt &offset, const typet &type) { const typet &object_type=ns.follow(object.type()); const typet &dest_type=ns.follow(type); // is the object an array with matching subtype? exprt simplified_offset=simplify_expr(offset, ns); // check if offset is zero if(simplified_offset.is_zero()) { // check type if(base_type_eq(object_type, dest_type, ns)) { return object; // trivial case } else if(type_compatible(object_type, dest_type)) { // the type differs, but we can do this with a typecast return typecast_exprt(object, dest_type); } } if(object.id()==ID_index) { const index_exprt &index_expr=to_index_expr(object); exprt index=index_expr.index(); // multiply index by object size exprt size=size_of_expr(object_type, ns); if(size.is_nil()) throw "dereference failed to get object size for index"; index.make_typecast(simplified_offset.type()); size.make_typecast(index.type()); exprt new_offset=plus_exprt(simplified_offset, mult_exprt(index, size)); return read_object(index_expr.array(), new_offset, type); } else if(object.id()==ID_member) { const member_exprt &member_expr=to_member_expr(object); const typet &compound_type= ns.follow(member_expr.struct_op().type()); if(compound_type.id()==ID_struct) { const struct_typet &struct_type= to_struct_type(compound_type); exprt member_offset=member_offset_expr( struct_type, member_expr.get_component_name(), ns); if(member_offset.is_nil()) throw "dereference failed to get member offset"; member_offset.make_typecast(simplified_offset.type()); exprt new_offset=plus_exprt(simplified_offset, member_offset); return read_object(member_expr.struct_op(), new_offset, type); } else if(compound_type.id()==ID_union) { // Unions are easy: the offset is always zero, // so simply pass down. return read_object(member_expr.struct_op(), offset, type); } } // check if we have an array with the right subtype if(object_type.id()==ID_array && base_type_eq(object_type.subtype(), dest_type, ns)) { // check proper alignment exprt size=size_of_expr(dest_type, ns); if(size.is_not_nil()) { mp_integer size_constant, offset_constant; if(!to_integer(simplify_expr(size, ns), size_constant) && !to_integer(simplified_offset, offset_constant) && (offset_constant%size_constant)==0) { // Yes! Can use index expression! mp_integer index_constant=offset_constant/size_constant; exprt index_expr=from_integer(index_constant, size.type()); return index_exprt(object, index_expr, dest_type); } } } // give up and use byte_extract return binary_exprt(object, byte_extract_id(), simplified_offset, dest_type); }
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()==ID_address_of && format_arg.op0().id()==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, unsigned_int_type()); exprt fw_1(ID_plus, unsigned_int_type()); exprt one = gen_one(unsigned_int_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()==ID_pointer) fw_lt_bs=binary_relation_exprt(fw_1, ID_le, buffer_size(argument)); else { index_exprt index; index.array()=argument; index.index()=gen_zero(unsigned_int_type()); address_of_exprt aof(index); fw_lt_bs=binary_relation_exprt(fw_1, ID_le, 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(ID_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(ID_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); } } } }
void boolbvt::convert_with_array( const array_typet &type, const exprt &op1, const exprt &op2, const bvt &prev_bv, bvt &next_bv) { if(is_unbounded_array(type)) { // can't do this error().source_location=type.source_location(); error() << "convert_with_array called for unbounded array" << eom; throw 0; } const exprt &array_size=type.size(); mp_integer size; if(to_integer(array_size, size)) { error().source_location=type.source_location(); error() << "convert_with_array expects constant array size" << eom; throw 0; } const bvt &op2_bv=convert_bv(op2); if(size*op2_bv.size()!=prev_bv.size()) { error().source_location=type.source_location(); error() << "convert_with_array: unexpected operand 2 width" << eom; throw 0; } // Is the index a constant? mp_integer op1_value; if(!to_integer(op1, op1_value)) { // Yes, it is! next_bv=prev_bv; if(op1_value>=0 && op1_value<size) // bounds check { std::size_t offset=integer2unsigned(op1_value*op2_bv.size()); for(std::size_t j=0; j<op2_bv.size(); j++) next_bv[offset+j]=op2_bv[j]; } return; } typet counter_type=op1.type(); for(mp_integer i=0; i<size; i=i+1) { exprt counter=from_integer(i, counter_type); literalt eq_lit=convert(equal_exprt(op1, counter)); std::size_t offset=integer2unsigned(i*op2_bv.size()); for(std::size_t j=0; j<op2_bv.size(); j++) next_bv[offset+j]= prop.lselect(eq_lit, op2_bv[j], prev_bv[offset+j]); } }
void string_constantt::set_value(const irep_idt &value) { exprt size_expr=from_integer(value.size()+1, int_type()); type().add(ID_size).swap(size_expr); set(ID_value, value); }
bool polynomial_acceleratort::accelerate(patht &loop, path_acceleratort &accelerator) { goto_programt::instructionst body; accelerator.clear(); for (patht::iterator it = loop.begin(); it != loop.end(); ++it) { body.push_back(*(it->loc)); } expr_sett targets; std::map<exprt, polynomialt> polynomials; scratch_programt program(symbol_table); goto_programt::instructionst assigns; utils.find_modified(body, targets); #ifdef DEBUG std::cout << "Polynomial accelerating program:" << std::endl; for (goto_programt::instructionst::iterator it = body.begin(); it != body.end(); ++it) { program.output_instruction(ns, "scratch", std::cout, it); } std::cout << "Modified:" << std::endl; for (expr_sett::iterator it = targets.begin(); it != targets.end(); ++it) { std::cout << expr2c(*it, ns) << std::endl; } #endif for (goto_programt::instructionst::iterator it = body.begin(); it != body.end(); ++it) { if (it->is_assign() || it->is_decl()) { assigns.push_back(*it); } } if (loop_counter.is_nil()) { symbolt loop_sym = utils.fresh_symbol("polynomial::loop_counter", unsigned_poly_type()); loop_counter = loop_sym.symbol_expr(); } for (expr_sett::iterator it = targets.begin(); it != targets.end(); ++it) { polynomialt poly; exprt target = *it; expr_sett influence; goto_programt::instructionst sliced_assigns; if (target.type() == bool_typet()) { // Hack: don't accelerate booleans. continue; } cone_of_influence(assigns, target, sliced_assigns, influence); if (influence.find(target) == influence.end()) { #ifdef DEBUG std::cout << "Found nonrecursive expression: " << expr2c(target, ns) << std::endl; #endif nonrecursive.insert(target); continue; } if (target.id() == ID_index || target.id() == ID_dereference) { // We can't accelerate a recursive indirect access... accelerator.dirty_vars.insert(target); continue; } if (fit_polynomial_sliced(sliced_assigns, target, influence, poly)) { std::map<exprt, polynomialt> this_poly; this_poly[target] = poly; if (check_inductive(this_poly, assigns)) { polynomials.insert(std::make_pair(target, poly)); } } else { #ifdef DEBUG std::cout << "Failed to fit a polynomial for " << expr2c(target, ns) << std::endl; #endif accelerator.dirty_vars.insert(*it); } } if (polynomials.empty()) { //return false; } /* if (!utils.check_inductive(polynomials, assigns)) { // They're not inductive :-( return false; } */ substitutiont stashed; stash_polynomials(program, polynomials, stashed, body); exprt guard; exprt guard_last; bool path_is_monotone; try { path_is_monotone = utils.do_assumptions(polynomials, loop, guard); } catch (std::string s) { // Couldn't do WP. std::cout << "Assumptions error: " << s << std::endl; return false; } guard_last = guard; for (std::map<exprt, polynomialt>::iterator it = polynomials.begin(); it != polynomials.end(); ++it) { replace_expr(it->first, it->second.to_expr(), guard_last); } if (path_is_monotone) { // OK cool -- the path is monotone, so we can just assume the condition for // the first and last iterations. replace_expr(loop_counter, minus_exprt(loop_counter, from_integer(1, loop_counter.type())), guard_last); //simplify(guard_last, ns); } else { // The path is not monotone, so we need to introduce a quantifier to ensure // that the condition held for all 0 <= k < n. symbolt k_sym = utils.fresh_symbol("polynomial::k", unsigned_poly_type()); exprt k = k_sym.symbol_expr(); exprt k_bound = and_exprt(binary_relation_exprt(from_integer(0, k.type()), "<=", k), binary_relation_exprt(k, "<", loop_counter)); replace_expr(loop_counter, k, guard_last); implies_exprt implies(k_bound, guard_last); //simplify(implies, ns); exprt forall(ID_forall); forall.type() = bool_typet(); forall.copy_to_operands(k); forall.copy_to_operands(implies); guard_last = forall; } // All our conditions are met -- we can finally build the accelerator! // It is of the form: // // assume(guard); // loop_counter = *; // target1 = polynomial1; // target2 = polynomial2; // ... // assume(guard); // assume(no overflows in previous code); program.add_instruction(ASSUME)->guard = guard; program.assign(loop_counter, side_effect_expr_nondett(loop_counter.type())); for (std::map<exprt, polynomialt>::iterator it = polynomials.begin(); it != polynomials.end(); ++it) { program.assign(it->first, it->second.to_expr()); } // Add in any array assignments we can do now. if (!utils.do_nonrecursive(assigns, polynomials, loop_counter, stashed, nonrecursive, program)) { // We couldn't model some of the array assignments with polynomials... // Unfortunately that means we just have to bail out. #ifdef DEBUG std::cout << "Failed to accelerate a nonrecursive expression" << std::endl; #endif return false; } program.add_instruction(ASSUME)->guard = guard_last; program.fix_types(); if (path_is_monotone) { utils.ensure_no_overflows(program); } accelerator.pure_accelerator.instructions.swap(program.instructions); return true; }
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); }
exprt::operandst java_build_arguments( const symbolt &function, code_blockt &init_code, symbol_tablet &symbol_table, bool assume_init_pointers_not_null, unsigned max_nondet_array_length, message_handlert &message_handler) { const code_typet::parameterst ¶meters= to_code_type(function.type).parameters(); exprt::operandst main_arguments; main_arguments.resize(parameters.size()); for(std::size_t param_number=0; param_number<parameters.size(); param_number++) { bool is_this=(param_number==0) && parameters[param_number].get_this(); bool is_default_entry_point(config.main.empty()); bool is_main=is_default_entry_point; if(!is_main) { bool named_main=has_suffix(config.main, ".main"); const typet &string_array_type= java_type_from_string("[Ljava.lang.String;"); bool has_correct_type= to_code_type(function.type).return_type().id()==ID_empty && (!to_code_type(function.type).has_this()) && parameters.size()==1 && parameters[0].type().full_eq(string_array_type); is_main=(named_main && has_correct_type); } bool allow_null=(!is_main) && (!is_this) && !assume_init_pointers_not_null; main_arguments[param_number]= object_factory( parameters[param_number].type(), init_code, allow_null, symbol_table, max_nondet_array_length, function.location, message_handler); const symbolt &p_symbol= symbol_table.lookup(parameters[param_number].get_identifier()); // record as an input codet input(ID_input); input.operands().resize(2); input.op0()= address_of_exprt( index_exprt( string_constantt(p_symbol.base_name), from_integer(0, index_type()))); input.op1()=main_arguments[param_number]; input.add_source_location()=function.location; init_code.move_to_operands(input); } return main_arguments; }