exprt ssa_alias_guard( const exprt &e1, const exprt &e2, const namespacet &ns) { exprt a1=address_canonizer(address_of_exprt(e1), ns); exprt a2=address_canonizer(address_of_exprt(e2), ns); // in some cases, we can use plain address equality, // as we assume well-aligned-ness mp_integer size1=pointer_offset_size(e1.type(), ns); mp_integer size2=pointer_offset_size(e2.type(), ns); if(size1>=size2) { exprt lhs=a1; exprt rhs=a2; if(ns.follow(rhs.type())!=ns.follow(lhs.type())) rhs=typecast_exprt(rhs, lhs.type()); return equal_exprt(lhs, rhs); } return same_object(a1, a2); }
exprt ssa_alias_guard( const exprt &e1, const exprt &e2, const namespacet &ns) { exprt a1=address_canonizer(address_of_exprt(e1), ns); // TODO: We should compare 'base' pointers here because // we have a higher chance that there was no pointer arithmetic // on the base pointer than that the result of the pointer // arithmetic points to a base pointer. // The following hack does that: if(a1.id()==ID_plus) a1=a1.op0(); exprt a2=address_canonizer(address_of_exprt(e2), ns); // in some cases, we can use plain address equality, // as we assume well-aligned-ness mp_integer size1=pointer_offset_size(e1.type(), ns); mp_integer size2=pointer_offset_size(e2.type(), ns); if(size1>=size2) { exprt lhs=a1; exprt rhs=a2; if(ns.follow(rhs.type())!=ns.follow(lhs.type())) rhs=typecast_exprt(rhs, lhs.type()); return equal_exprt(lhs, rhs); } return same_object(a1, a2); }
void rd_range_domaint::assign( const namespacet &ns, locationt from, const exprt &lhs, const mp_integer &range_start, const mp_integer &size) { if(lhs.id()==ID_member) assign(ns, from, to_member_expr(lhs).struct_op(), range_start, size); else if(lhs.id()==ID_index) assign(ns, from, to_index_expr(lhs).array(), range_start, size); else { const symbol_exprt &symbol=to_symbol_expr(lhs); const irep_idt identifier=symbol.get_identifier(); if(range_start>=0) { kill(from, identifier, range_start, size); gen(from, identifier, range_start, size); } else { mp_integer full_size=pointer_offset_size(ns, symbol.type()); gen(from, identifier, 0, full_size); } } }
mp_integer compute_pointer_offset( const namespacet &ns, const exprt &expr) { if(expr.id()==ID_symbol) return 0; else if(expr.id()==ID_index) { assert(expr.operands().size()==2); const typet &array_type=ns.follow(expr.op0().type()); assert(array_type.id()==ID_array); mp_integer o=compute_pointer_offset(ns, expr.op0()); if(o!=-1) { mp_integer sub_size= pointer_offset_size(ns, array_type.subtype()); mp_integer i; if(sub_size!=0 && !to_integer(expr.op1(), i)) return o+i*sub_size; } // don't know } else if(expr.id()==ID_member) { assert(expr.operands().size()==1); const typet &type=ns.follow(expr.op0().type()); assert(type.id()==ID_struct || type.id()==ID_union); mp_integer o=compute_pointer_offset(ns, expr.op0()); if(o!=-1) { if(type.id()==ID_union) return o; return o+member_offset( ns, to_struct_type(type), expr.get(ID_component_name)); } } else if(expr.id()==ID_string_constant) return 0; return -1; // don't know }
void rd_range_domaint::transform( const namespacet &ns, locationt from, locationt to) { if(from->is_dead()) { const symbol_exprt &symbol= to_symbol_expr(to_code_dead(from->code).symbol()); values.erase(symbol.get_identifier()); return; } else if(!from->is_assign()) return; const exprt &lhs=to_code_assign(from->code).lhs(); if(lhs.id()==ID_complex_real || lhs.id()==ID_complex_imag) { assert(lhs.type().id()==ID_complex); mp_integer offset=compute_pointer_offset(ns, lhs.op0()); mp_integer sub_size=pointer_offset_size(ns, lhs.type().subtype()); assign( ns, from, lhs.op0(), offset+((offset==-1 || lhs.id()==ID_complex_real) ? 0 : sub_size), sub_size); } else { mp_integer size=pointer_offset_size(ns, lhs.type()); assign(ns, from, lhs, size); } }
exprt ssa_alias_value( const exprt &e1, const exprt &e2, const namespacet &ns) { const typet &e1_type=ns.follow(e1.type()); const typet &e2_type=ns.follow(e2.type()); // type matches? if(e1_type==e2_type) return e2; exprt a1=address_canonizer(address_of_exprt(e1), ns); exprt a2=address_canonizer(address_of_exprt(e2), ns); exprt offset1=pointer_offset(a1); // array index possible? if(e2_type.id()==ID_array && e1_type==ns.follow(e2_type.subtype())) { // this assumes well-alignedness mp_integer element_size=pointer_offset_size(e2_type.subtype(), ns); if(element_size==1) return index_exprt(e2, offset1, e1.type()); else if(element_size>1) { exprt index= div_exprt(offset1, from_integer(element_size, offset1.type())); return index_exprt(e2, index, e1.type()); } } byte_extract_exprt byte_extract(byte_extract_id(), e1.type()); byte_extract.op()=e2; byte_extract.offset()=offset1; return byte_extract; }
mp_integer member_offset( const namespacet &ns, const struct_typet &type, const irep_idt &member) { const struct_typet::componentst &components=type.components(); mp_integer result=0; unsigned bit_field_bits=0; for(struct_typet::componentst::const_iterator it=components.begin(); it!=components.end(); it++) { if(it->get_name()==member) break; if(it->get_is_bit_field()) { bit_field_bits+=it->type().get_int(ID_width); } else { if(bit_field_bits!=0) { result+=bit_field_bits/8; bit_field_bits=0; } const typet &subtype=it->type(); mp_integer sub_size=pointer_offset_size(ns, subtype); if(sub_size==-1) return -1; // give up result+=sub_size; } } return result; }
value_set_dereferencet::valuet value_set_dereferencet::build_reference_to( const exprt &what, const modet mode, const exprt &pointer_expr, const guardt &guard) { const typet &dereference_type= ns.follow(pointer_expr.type()).subtype(); if(what.id()==ID_unknown || what.id()==ID_invalid) { invalid_pointer(pointer_expr, guard); return valuet(); } if(what.id()!=ID_object_descriptor) throw "unknown points-to: "+what.id_string(); const object_descriptor_exprt &o=to_object_descriptor_expr(what); const exprt &root_object=o.root_object(); const exprt &object=o.object(); #if 0 std::cout << "O: " << from_expr(ns, "", root_object) << '\n'; #endif valuet result; if(root_object.id()=="NULL-object") { if(options.get_bool_option("pointer-check")) { guardt tmp_guard(guard); if(o.offset().is_zero()) { tmp_guard.add(null_pointer(pointer_expr)); dereference_callback.dereference_failure( "pointer dereference", "NULL pointer", tmp_guard); } else { tmp_guard.add(null_object(pointer_expr)); dereference_callback.dereference_failure( "pointer dereference", "NULL plus offset pointer", tmp_guard); } } } else if(root_object.id()==ID_dynamic_object) { // const dynamic_object_exprt &dynamic_object= // to_dynamic_object_expr(root_object); // the object produced by malloc exprt malloc_object= ns.lookup(CPROVER_PREFIX "malloc_object").symbol_expr(); exprt is_malloc_object=same_object(pointer_expr, malloc_object); // constraint that it actually is a dynamic object exprt dynamic_object_expr(ID_dynamic_object, bool_typet()); dynamic_object_expr.copy_to_operands(pointer_expr); // this is also our guard result.pointer_guard=dynamic_object_expr; // can't remove here, turn into *p result.value=dereference_exprt(pointer_expr, dereference_type); if(options.get_bool_option("pointer-check")) { // if(!dynamic_object.valid().is_true()) { // check if it is still alive guardt tmp_guard(guard); tmp_guard.add(deallocated(pointer_expr, ns)); dereference_callback.dereference_failure( "pointer dereference", "dynamic object deallocated", tmp_guard); } if(options.get_bool_option("bounds-check")) { if(!o.offset().is_zero()) { // check lower bound guardt tmp_guard(guard); tmp_guard.add(is_malloc_object); tmp_guard.add( dynamic_object_lower_bound( pointer_expr, ns, nil_exprt())); dereference_callback.dereference_failure( "pointer dereference", "dynamic object lower bound", tmp_guard); } { // check upper bound // we check SAME_OBJECT(__CPROVER_malloc_object, p) && // POINTER_OFFSET(p)+size>__CPROVER_malloc_size guardt tmp_guard(guard); tmp_guard.add(is_malloc_object); tmp_guard.add( dynamic_object_upper_bound( pointer_expr, dereference_type, ns, size_of_expr(dereference_type, ns))); dereference_callback.dereference_failure( "pointer dereference", "dynamic object upper bound", tmp_guard); } } } } else if(root_object.id()==ID_integer_address) { // This is stuff like *((char *)5). // This is turned into an access to __CPROVER_memory[...]. if(language_mode==ID_java) { result.value=nil_exprt(); return result; } const symbolt &memory_symbol=ns.lookup(CPROVER_PREFIX "memory"); exprt symbol_expr=symbol_exprt(memory_symbol.name, memory_symbol.type); if(base_type_eq( ns.follow(memory_symbol.type).subtype(), dereference_type, ns)) { // Types match already, what a coincidence! // We can use an index expression. exprt index_expr=index_exprt(symbol_expr, pointer_offset(pointer_expr)); index_expr.type()=ns.follow(memory_symbol.type).subtype(); result.value=index_expr; } else if(dereference_type_compare( ns.follow(memory_symbol.type).subtype(), dereference_type)) { exprt index_expr=index_exprt(symbol_expr, pointer_offset(pointer_expr)); index_expr.type()=ns.follow(memory_symbol.type).subtype(); result.value=typecast_exprt(index_expr, dereference_type); } else { // We need to use byte_extract. // Won't do this without a commitment to an endianness. if(config.ansi_c.endianness==configt::ansi_ct::endiannesst::NO_ENDIANNESS) { } else { exprt byte_extract(byte_extract_id(), dereference_type); byte_extract.copy_to_operands( symbol_expr, pointer_offset(pointer_expr)); result.value=byte_extract; } } } else { // something generic -- really has to be a symbol address_of_exprt object_pointer(object); if(o.offset().is_zero()) { equal_exprt equality(pointer_expr, object_pointer); if(ns.follow(equality.lhs().type())!=ns.follow(equality.rhs().type())) equality.lhs().make_typecast(equality.rhs().type()); result.pointer_guard=equality; } else { result.pointer_guard=same_object(pointer_expr, object_pointer); } guardt tmp_guard(guard); tmp_guard.add(result.pointer_guard); valid_check(object, tmp_guard, mode); const typet &object_type=ns.follow(object.type()); const exprt &root_object=o.root_object(); const typet &root_object_type=ns.follow(root_object.type()); exprt root_object_subexpression=root_object; if(dereference_type_compare(object_type, dereference_type) && o.offset().is_zero()) { // The simplest case: types match, and offset is zero! // This is great, we are almost done. result.value=object; if(object_type!=ns.follow(dereference_type)) result.value.make_typecast(dereference_type); } else if(root_object_type.id()==ID_array && dereference_type_compare( root_object_type.subtype(), dereference_type)) { // We have an array with a subtype that matches // the dereferencing type. // We will require well-alignedness! exprt offset; // this should work as the object is essentially the root object if(o.offset().is_constant()) offset=o.offset(); else offset=pointer_offset(pointer_expr); exprt adjusted_offset; // are we doing a byte? mp_integer element_size= dereference_type.id()==ID_empty? pointer_offset_size(char_type(), ns): pointer_offset_size(dereference_type, ns); if(element_size==1) { // no need to adjust offset adjusted_offset=offset; } else if(element_size<=0) { throw "unknown or invalid type size of:\n"+dereference_type.pretty(); } else { exprt element_size_expr= from_integer(element_size, offset.type()); adjusted_offset=binary_exprt( offset, ID_div, element_size_expr, offset.type()); // TODO: need to assert well-alignedness } index_exprt index_expr= index_exprt(root_object, adjusted_offset, root_object_type.subtype()); bounds_check(index_expr, tmp_guard); result.value=index_expr; if(ns.follow(result.value.type())!=ns.follow(dereference_type)) result.value.make_typecast(dereference_type); } else if(get_subexpression_at_offset( root_object_subexpression, o.offset(), dereference_type, ns)) { // Successfully found a member, array index, or combination thereof // that matches the desired type and offset: result.value=root_object_subexpression; } else { // we extract something from the root object result.value=o.root_object(); // this is relative to the root object const exprt offset=pointer_offset(pointer_expr); if(memory_model(result.value, dereference_type, tmp_guard, offset)) { // ok, done } else { if(options.get_bool_option("pointer-check")) { std::string msg="memory model not applicable (got `"; msg+=from_type(ns, "", result.value.type()); msg+="', expected `"; msg+=from_type(ns, "", dereference_type); msg+="')"; dereference_callback.dereference_failure( "pointer dereference", msg, tmp_guard); } return valuet(); // give up, no way that this is ok } } } return result; }
exprt flatten_byte_extract( const exprt &src, const namespacet &ns) { assert(src.id()==ID_byte_extract_little_endian || src.id()==ID_byte_extract_big_endian); assert(src.operands().size()==2); bool little_endian; if(src.id()==ID_byte_extract_little_endian) little_endian=true; else if(src.id()==ID_byte_extract_big_endian) little_endian=false; else assert(false); if(src.id()==ID_byte_extract_big_endian) throw "byte_extract flattening of big endian not done yet"; unsigned width= integer2long(pointer_offset_size(ns, src.type())); const typet &t=src.op0().type(); if(t.id()==ID_array) { const array_typet &array_type=to_array_type(t); const typet &subtype=array_type.subtype(); // byte-array? if((subtype.id()==ID_unsignedbv || subtype.id()==ID_signedbv) && subtype.get_int(ID_width)==8) { // get 'width'-many bytes, and concatenate exprt::operandst op; op.resize(width); for(unsigned i=0; i<width; i++) { // the most significant byte comes first in the concatenation! unsigned offset_i= little_endian?(width-i-1):i; plus_exprt offset(from_integer(offset_i, src.op1().type()), src.op1()); index_exprt index_expr(subtype); index_expr.array()=src.op0(); index_expr.index()=offset; op[i]=index_expr; } if(width==1) return op[0]; else // width>=2 { concatenation_exprt concatenation(src.type()); concatenation.operands().swap(op); return concatenation; } } else // non-byte array { const exprt &root=src.op0(); const exprt &offset=src.op1(); const typet &array_type=ns.follow(root.type()); const typet &offset_type=ns.follow(offset.type()); const typet &element_type=ns.follow(array_type.subtype()); mp_integer element_width=pointer_offset_size(ns, element_type); if(element_width==-1) // failed throw "failed to flatten non-byte array with unknown element width"; mp_integer result_width=pointer_offset_size(ns, src.type()); mp_integer num_elements=(element_width+result_width-2)/element_width+1; // compute new root and offset concatenation_exprt concat( unsignedbv_typet(integer2long(element_width*8*num_elements))); exprt first_index= (element_width==1)?offset : div_exprt(offset, from_integer(element_width, offset_type)); // 8*offset/el_w for(mp_integer i=num_elements; i>0; --i) { plus_exprt index(first_index, from_integer(i-1, offset_type)); concat.copy_to_operands(index_exprt(root, index)); } // the new offset is width%offset exprt new_offset= (element_width==1)?from_integer(0, offset_type): mod_exprt(offset, from_integer(element_width, offset_type)); // build new byte-extract expression exprt tmp(src.id(), src.type()); tmp.copy_to_operands(concat, new_offset); return tmp; } } else // non-array { // We turn that into logical right shift and extractbits const exprt &offset=src.op1(); const typet &offset_type=ns.follow(offset.type()); mult_exprt times_eight(offset, from_integer(8, offset_type)); lshr_exprt left_shift(src.op0(), times_eight); extractbits_exprt extractbits; extractbits.src()=left_shift; extractbits.type()=src.type(); extractbits.upper()=from_integer(width*8-1, offset_type); extractbits.lower()=from_integer(0, offset_type); return extractbits; } }
exprt flatten_byte_update( const exprt &src, const namespacet &ns) { assert(src.id()==ID_byte_update_little_endian || src.id()==ID_byte_update_big_endian); assert(src.operands().size()==3); mp_integer element_size= pointer_offset_size(ns, src.op2().type()); const typet &t=ns.follow(src.op0().type()); if(t.id()==ID_array) { const array_typet &array_type=to_array_type(t); const typet &subtype=array_type.subtype(); // array of bitvectors? if(subtype.id()==ID_unsignedbv || subtype.id()==ID_signedbv || subtype.id()==ID_floatbv) { mp_integer sub_size=pointer_offset_size(ns, subtype); if(sub_size==-1) throw "can't flatten byte_update for sub-type without size"; // byte array? if(sub_size==1) { // apply 'array-update-with' element_size times exprt result=src.op0(); for(mp_integer i=0; i<element_size; ++i) { exprt i_expr=from_integer(i, ns.follow(src.op1().type())); exprt new_value; if(i==0 && element_size==1) // bytes? { new_value=src.op2(); if(new_value.type()!=subtype) new_value.make_typecast(subtype); } else { exprt byte_extract_expr( src.id()==ID_byte_update_little_endian?ID_byte_extract_little_endian: src.id()==ID_byte_update_big_endian?ID_byte_extract_big_endian: throw "unexpected src.id()", subtype); byte_extract_expr.copy_to_operands(src.op2(), i_expr); new_value=flatten_byte_extract(byte_extract_expr, ns); } exprt where=plus_exprt(src.op1(), i_expr); with_exprt with_expr; with_expr.type()=src.type(); with_expr.old()=result; with_expr.where()=where; with_expr.new_value()=new_value; result.swap(with_expr); } return result; } else // sub_size!=1 { if(element_size==1) // byte-granularity update { div_exprt div_offset(src.op1(), from_integer(sub_size, src.op1().type())); mod_exprt mod_offset(src.op1(), from_integer(sub_size, src.op1().type())); index_exprt index_expr(src.op0(), div_offset, array_type.subtype()); exprt byte_update_expr(src.id(), array_type.subtype()); byte_update_expr.copy_to_operands(index_expr, mod_offset, src.op2()); // Call recurisvely, the array is gone! exprt flattened_byte_update_expr= flatten_byte_update(byte_update_expr, ns); with_exprt with_expr( src.op0(), div_offset, flattened_byte_update_expr); return with_expr; } else throw "flatten_byte_update can only do byte updates of non-byte arrays right now"; } } else { throw "flatten_byte_update can only do arrays of scalars right now"; } } else if(t.id()==ID_signedbv || t.id()==ID_unsignedbv || t.id()==ID_floatbv) { // do a shift, mask and OR unsigned width=to_bitvector_type(t).get_width(); if(element_size*8>width) throw "flatten_byte_update to update element that is too large"; // build mask exprt mask= bitnot_exprt( from_integer(power(2, element_size*8)-1, unsignedbv_typet(width))); const typet &offset_type=ns.follow(src.op1().type()); mult_exprt offset_times_eight(src.op1(), from_integer(8, offset_type)); // shift the mask shl_exprt shl_expr(mask, offset_times_eight); // do the 'AND' bitand_exprt bitand_expr(src.op0(), mask); // zero-extend the value concatenation_exprt value_extended( from_integer(0, unsignedbv_typet(width-integer2long(element_size)*8)), src.op2(), t); // shift the value shl_exprt value_shifted(value_extended, offset_times_eight); // do the 'OR' bitor_exprt bitor_expr(bitand_expr, value_shifted); return bitor_expr; } else { throw "flatten_byte_update can only do array and scalars right now"; } }
void add_padding(struct_typet &type, const namespacet &ns) { struct_typet::componentst &components=type.components(); // first do padding for bit-fields { unsigned padding_counter=0; unsigned bit_field_bits=0; for(struct_typet::componentst::iterator it=components.begin(); it!=components.end(); it++) { if(it->get_is_bit_field()) { // count the bits bit_field_bits+=it->type().get_int(ID_width); } else if(bit_field_bits!=0) { // not on a byte-boundary? if((bit_field_bits%8)!=0) { unsigned pad=8-bit_field_bits%8; unsignedbv_typet padding_type; padding_type.set_width(pad); struct_typet::componentt component; component.type()=padding_type; component.set_name("$bit_field_pad"+i2string(padding_counter++)); component.set_is_padding(true); component.set_is_bit_field(true); it=components.insert(it, component); it++; // skip over bit_field_bits+=pad; } bit_field_bits=0; } } // Add padding at the end? if((bit_field_bits%8)!=0) { unsigned pad=8-bit_field_bits%8; unsignedbv_typet padding_type; padding_type.set_width(pad); struct_typet::componentt component; component.type()=padding_type; component.set_name("$bit_field_pad"+i2string(padding_counter++)); component.set_is_padding(true); component.set_is_bit_field(true); components.push_back(component); } } // packed? if(type.get_bool(ID_packed)) return; // done mp_integer offset=0; unsigned padding_counter=0; unsigned max_alignment=0; unsigned bit_field_bits=0; for(struct_typet::componentst::iterator it=components.begin(); it!=components.end(); it++) { // ANSI-C says that bit-fields do not get padded! if(it->get_is_bit_field()) { // count the bits bit_field_bits+=it->type().get_int(ID_width); // we consider the type for max_alignment, however unsigned a=alignment(it->get_bit_field_type(), ns); if(max_alignment<a) max_alignment=a; continue; } else if(bit_field_bits!=0) { // these are now assumed to be multiples of 8 offset+=bit_field_bits/8; bit_field_bits=0; } const typet &it_type=it->type(); unsigned a=alignment(it_type, ns); // check minimum alignment if(a<config.ansi_c.alignment) a=config.ansi_c.alignment; if(max_alignment<a) max_alignment=a; if(a!=1) { // we may need to align it unsigned displacement=integer2long(offset%a); if(displacement!=0) { unsigned pad=a-displacement; unsignedbv_typet padding_type; padding_type.set_width(pad*8); struct_typet::componentt component; component.type()=padding_type; component.set_name("$pad"+i2string(padding_counter++)); component.set_is_padding(true); it=components.insert(it, component); it++; // skip over offset+=pad; } } mp_integer size=pointer_offset_size(ns, it_type); if(size!=-1) offset+=size; } if(bit_field_bits!=0) { // these are now assumed to be multiples of 8 offset+=bit_field_bits/8; } // There may be a need for 'end of struct' padding. // We use 'max_alignment'. if(max_alignment>1) { // we may need to align it unsigned displacement=integer2long(offset%max_alignment); if(displacement!=0) { unsigned pad=max_alignment-displacement; unsignedbv_typet padding_type; padding_type.set_width(pad*8); struct_typet::componentst::iterator it; // we need to insert before any 'flexible member' if(!components.empty() && components.back().type().id()==ID_array && to_array_type(components.back().type()).size().is_zero()) { it=components.end(); it--; } else it=components.end(); struct_typet::componentt component; component.type()=padding_type; component.set_name("$pad"+i2string(padding_counter++)); component.set_is_padding(true); components.insert(it, component); } } }
exprt pointer_logict::object_rec( const mp_integer &offset, const typet &pointer_type, const exprt &src) const { if(src.type().id()==ID_array) { mp_integer size= pointer_offset_size(src.type().subtype(), ns); if(size<=0) return src; mp_integer index=offset/size; mp_integer rest=offset%size; if(rest<0) rest=-rest; index_exprt tmp(src.type().subtype()); tmp.index()=from_integer(index, typet(ID_integer)); tmp.array()=src; return object_rec(rest, pointer_type, tmp); } else if(src.type().id()==ID_struct) { const struct_typet::componentst &components= to_struct_type(src.type()).components(); if(offset<0) return src; mp_integer current_offset=0; for(struct_typet::componentst::const_iterator it=components.begin(); it!=components.end(); it++) { assert(offset>=current_offset); const typet &subtype=it->type(); mp_integer sub_size=pointer_offset_size(subtype, ns); assert(sub_size>0); mp_integer new_offset=current_offset+sub_size; if(new_offset>offset) { // found it member_exprt tmp(subtype); tmp.set_component_name(it->get_name()); tmp.op0()=src; return object_rec( offset-current_offset, pointer_type, tmp); } assert(new_offset<=offset); current_offset=new_offset; assert(current_offset<=offset); } return src; } else if(src.type().id()==ID_union) return src; return src; }
void value_sett::get_value_set_rec( const exprt &expr, object_mapt &dest, const std::string &suffix, const typet &original_type, const namespacet &ns) const { #if 0 std::cout << "GET_VALUE_SET_REC EXPR: " << from_expr(ns, "", expr) << "\n"; std::cout << "GET_VALUE_SET_REC SUFFIX: " << suffix << std::endl; #endif const typet &expr_type=ns.follow(expr.type()); if(expr.id()==ID_unknown || expr.id()==ID_invalid) { insert(dest, exprt(ID_unknown, original_type)); } else if(expr.id()==ID_index) { assert(expr.operands().size()==2); const typet &type=ns.follow(expr.op0().type()); assert(type.id()==ID_array || type.id()==ID_incomplete_array); get_value_set_rec(expr.op0(), dest, "[]"+suffix, original_type, ns); } else if(expr.id()==ID_member) { assert(expr.operands().size()==1); const typet &type=ns.follow(expr.op0().type()); assert(type.id()==ID_struct || type.id()==ID_union || type.id()==ID_incomplete_struct || type.id()==ID_incomplete_union); const std::string &component_name= expr.get_string(ID_component_name); get_value_set_rec(expr.op0(), dest, "."+component_name+suffix, original_type, ns); } else if(expr.id()==ID_symbol) { irep_idt identifier=to_symbol_expr(expr).get_identifier(); // is it a pointer, integer, array or struct? if(expr_type.id()==ID_pointer || expr_type.id()==ID_signedbv || expr_type.id()==ID_unsignedbv || expr_type.id()==ID_struct || expr_type.id()==ID_union || expr_type.id()==ID_array) { // look it up valuest::const_iterator v_it= values.find(id2string(identifier)+suffix); // try first component name as suffix if not yet found if(v_it==values.end() && (expr_type.id()==ID_struct || expr_type.id()==ID_union)) { const struct_union_typet &struct_union_type= to_struct_union_type(expr_type); const std::string first_component_name= struct_union_type.components().front().get_string(ID_name); v_it=values.find( id2string(identifier)+"."+first_component_name+suffix); } // not found? try without suffix if(v_it==values.end()) v_it=values.find(identifier); if(v_it!=values.end()) make_union(dest, v_it->second.object_map); else insert(dest, exprt(ID_unknown, original_type)); } else insert(dest, exprt(ID_unknown, original_type)); } else if(expr.id()==ID_if) { if(expr.operands().size()!=3) throw "if takes three operands"; get_value_set_rec(expr.op1(), dest, suffix, original_type, ns); get_value_set_rec(expr.op2(), dest, suffix, original_type, ns); } else if(expr.id()==ID_address_of) { if(expr.operands().size()!=1) throw expr.id_string()+" expected to have one operand"; get_reference_set(expr.op0(), dest, ns); } else if(expr.id()==ID_dereference) { object_mapt reference_set; get_reference_set(expr, reference_set, ns); const object_map_dt &object_map=reference_set.read(); if(object_map.begin()==object_map.end()) insert(dest, exprt(ID_unknown, original_type)); else { for(object_map_dt::const_iterator it1=object_map.begin(); it1!=object_map.end(); it1++) { const exprt &object=object_numbering[it1->first]; get_value_set_rec(object, dest, suffix, original_type, ns); } } } else if(expr.id()=="reference_to") { // old stuff, will go away object_mapt reference_set; get_reference_set(expr, reference_set, ns); const object_map_dt &object_map=reference_set.read(); if(object_map.begin()==object_map.end()) insert(dest, exprt(ID_unknown, original_type)); else { for(object_map_dt::const_iterator it=object_map.begin(); it!=object_map.end(); it++) { const exprt &object=object_numbering[it->first]; get_value_set_rec(object, dest, suffix, original_type, ns); } } } else if(expr.is_constant()) { // check if NULL if(expr.get(ID_value)==ID_NULL && expr_type.id()==ID_pointer) { insert(dest, exprt("NULL-object", expr_type.subtype()), 0); } else if(expr_type.id()==ID_unsignedbv || expr_type.id()==ID_signedbv) { // an integer constant got turned into a pointer insert(dest, exprt(ID_integer_address, unsigned_char_type())); } else insert(dest, exprt(ID_unknown, original_type)); } else if(expr.id()==ID_typecast) { if(expr.operands().size()!=1) throw "typecast takes one operand"; // let's see what gets converted to what const typet &op_type=ns.follow(expr.op0().type()); if(op_type.id()==ID_pointer) { // pointer-to-pointer -- we just ignore these get_value_set_rec(expr.op0(), dest, suffix, original_type, ns); } else if(op_type.id()==ID_unsignedbv || op_type.id()==ID_signedbv) { // integer-to-pointer if(expr.op0().is_zero()) insert(dest, exprt("NULL-object", expr_type.subtype()), 0); else { // see if we have something for the integer object_mapt tmp; get_value_set_rec(expr.op0(), tmp, suffix, original_type, ns); if(tmp.read().size()==0) { // if not, throw in integer insert(dest, exprt(ID_integer_address, unsigned_char_type())); } else if(tmp.read().size()==1 && object_numbering[tmp.read().begin()->first].id()==ID_unknown) { // if not, throw in integer insert(dest, exprt(ID_integer_address, unsigned_char_type())); } else { // use as is dest.write().insert(tmp.read().begin(), tmp.read().end()); } } } else insert(dest, exprt(ID_unknown, original_type)); } else if(expr.id()==ID_plus || expr.id()==ID_minus) { if(expr.operands().size()<2) throw expr.id_string()+" expected to have at least two operands"; object_mapt pointer_expr_set; mp_integer i; bool i_is_set=false; // special case for pointer+integer if(expr.operands().size()==2 && expr_type.id()==ID_pointer) { exprt ptr_operand; if(expr.op0().type().id()!=ID_pointer && expr.op0().is_constant()) { i_is_set=!to_integer(expr.op0(), i); ptr_operand=expr.op1(); } else { i_is_set=!to_integer(expr.op1(), i); ptr_operand=expr.op0(); } if(i_is_set) { i*=pointer_offset_size(ptr_operand.type().subtype(), ns); if(expr.id()==ID_minus) i.negate(); } get_value_set_rec( ptr_operand, pointer_expr_set, "", ptr_operand.type(), ns); } else { // we get the points-to for all operands, even integers forall_operands(it, expr) { get_value_set_rec( *it, pointer_expr_set, "", it->type(), ns); } } for(object_map_dt::const_iterator it=pointer_expr_set.read().begin(); it!=pointer_expr_set.read().end(); it++) { objectt object=it->second; // adjust by offset if(object.offset_is_zero() && i_is_set) object.offset=i; else object.offset_is_set=false; insert(dest, it->first, object); } }
mp_integer pointer_offset_size( const namespacet &ns, const typet &type) { if(type.id()==ID_array) { mp_integer sub=pointer_offset_size(ns, type.subtype()); // get size const exprt &size=to_array_type(type).size(); // constant? mp_integer i; if(to_integer(size, i)) return -1; // we cannot distinguish the elements return sub*i; } else if(type.id()==ID_struct) { const struct_typet &struct_type=to_struct_type(type); const struct_typet::componentst &components= struct_type.components(); mp_integer result=0; unsigned bit_field_bits=0; for(struct_typet::componentst::const_iterator it=components.begin(); it!=components.end(); it++) { if(it->get_is_bit_field()) { bit_field_bits+=it->type().get_int(ID_width); } else { if(bit_field_bits!=0) { result+=bit_field_bits/8; bit_field_bits=0; } const typet &subtype=it->type(); mp_integer sub_size=pointer_offset_size(ns, subtype); if(sub_size==-1) return -1; result+=sub_size; } } return result; } else if(type.id()==ID_union) { const union_typet &union_type=to_union_type(type); const union_typet::componentst &components= union_type.components(); mp_integer result=0; // compute max for(union_typet::componentst::const_iterator it=components.begin(); it!=components.end(); it++) { const typet &subtype=it->type(); mp_integer sub_size=pointer_offset_size(ns, subtype); if(sub_size>result) result=sub_size; } return result; } else if(type.id()==ID_signedbv || type.id()==ID_unsignedbv || type.id()==ID_fixedbv || type.id()==ID_floatbv || type.id()==ID_bv || type.id()==ID_c_enum) { unsigned width=to_bitvector_type(type).get_width(); unsigned bytes=width/8; if(bytes*8!=width) bytes++; return bytes; } else if(type.id()==ID_bool) return 1; else if(type.id()==ID_pointer) { unsigned width=config.ansi_c.pointer_width; unsigned bytes=width/8; if(bytes*8!=width) bytes++; return bytes; } else if(type.id()==ID_symbol) return pointer_offset_size(ns, ns.follow(type)); else if(type.id()==ID_code) return 0; else return mp_integer(-1); }
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 add_padding(struct_typet &type, const namespacet &ns) { struct_typet::componentst &components=type.components(); // First do padding for bit-fields to make them // appear on byte boundaries. { unsigned padding_counter=0; unsigned bit_field_bits=0; for(struct_typet::componentst::iterator it=components.begin(); it!=components.end(); it++) { if(it->type().id()==ID_c_bit_field && to_c_bit_field_type(it->type()).get_width()!=0) { // count the bits unsigned width=to_c_bit_field_type(it->type()).get_width(); bit_field_bits+=width; } else if(bit_field_bits!=0) { // not on a byte-boundary? if((bit_field_bits%8)!=0) { unsigned pad=8-bit_field_bits%8; c_bit_field_typet padding_type(unsignedbv_typet(pad), pad); struct_typet::componentt component; component.type()=padding_type; component.set_name("$bit_field_pad"+i2string(padding_counter++)); component.set_is_padding(true); it=components.insert(it, component); it++; // skip over bit_field_bits+=pad; } bit_field_bits=0; } } // Add padding at the end? if((bit_field_bits%8)!=0) { unsigned pad=8-bit_field_bits%8; c_bit_field_typet padding_type(unsignedbv_typet(pad), pad); struct_typet::componentt component; component.type()=padding_type; component.set_name("$bit_field_pad"+i2string(padding_counter++)); component.set_is_padding(true); components.push_back(component); } } // Is the struct packed? if(type.get_bool(ID_C_packed)) return; // done mp_integer offset=0; unsigned padding_counter=0; mp_integer max_alignment=0; unsigned bit_field_bits=0; for(struct_typet::componentst::iterator it=components.begin(); it!=components.end(); it++) { const typet &it_type=it->type(); mp_integer a=1; if(it_type.id()==ID_c_bit_field) { a=alignment(to_c_bit_field_type(it_type).subtype(), ns); // A zero-width bit-field causes alignment to the base-type. if(to_c_bit_field_type(it_type).get_width()==0) { } else { // Otherwise, ANSI-C says that bit-fields do not get padded! // We consider the type for max_alignment, however. if(max_alignment<a) max_alignment=a; unsigned w=to_c_bit_field_type(it_type).get_width(); unsigned bytes; for(bytes=0; w>bit_field_bits; ++bytes, bit_field_bits+=8); bit_field_bits-=w; offset+=bytes; continue; } } else if(it->type().get_bool(ID_C_packed) || ns.follow(it->type()).get_bool(ID_C_packed)) { // the field or type is "packed" } else a=alignment(it_type, ns); // check minimum alignment if(a<config.ansi_c.alignment) a=config.ansi_c.alignment; if(max_alignment<a) max_alignment=a; if(a!=1) { // we may need to align it mp_integer displacement=offset%a; if(displacement!=0) { mp_integer pad=a-displacement; unsignedbv_typet padding_type; padding_type.set_width(integer2unsigned(pad*8)); struct_typet::componentt component; component.type()=padding_type; component.set_name("$pad"+i2string(padding_counter++)); component.set_is_padding(true); it=components.insert(it, component); it++; // skip over offset+=pad; } } mp_integer size=pointer_offset_size(ns, it_type); if(size!=-1) offset+=size; } if(bit_field_bits!=0) { // these are now assumed to be multiples of 8 offset+=bit_field_bits/8; } // any explicit alignment for the struct? if(type.find(ID_C_alignment).is_not_nil()) { const exprt &alignment= static_cast<const exprt &>(type.find(ID_C_alignment)); if(alignment.id()!=ID_default) { exprt tmp=alignment; simplify(tmp, ns); mp_integer tmp_i; if(!to_integer(tmp, tmp_i) && tmp_i>max_alignment) max_alignment=tmp_i; } } // There may be a need for 'end of struct' padding. // We use 'max_alignment'. if(max_alignment>1) { // we may need to align it mp_integer displacement=offset%max_alignment; if(displacement!=0) { mp_integer pad=max_alignment-displacement; unsignedbv_typet padding_type; padding_type.set_width(integer2unsigned(pad*8)); // we insert after any final 'flexible member' struct_typet::componentt component; component.type()=padding_type; component.set_name("$pad"+i2string(padding_counter++)); component.set_is_padding(true); components.push_back(component); } } }
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; }
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; }
std::string as_vcd_binary( const exprt &expr, const namespacet &ns) { const typet &type=ns.follow(expr.type()); if(expr.id()==ID_constant) { if(type.id()==ID_unsignedbv || type.id()==ID_signedbv || type.id()==ID_bv || type.id()==ID_fixedbv || type.id()==ID_floatbv || type.id()==ID_pointer) return expr.get_string(ID_value); } else if(expr.id()==ID_array) { std::string result; forall_operands(it, expr) result+=as_vcd_binary(*it, ns); return result; } else if(expr.id()==ID_struct) { std::string result; forall_operands(it, expr) result+=as_vcd_binary(*it, ns); return result; } else if(expr.id()==ID_union) { assert(expr.operands().size()==1); return as_vcd_binary(expr.op0(), ns); } // build "xxx" mp_integer width; if(type.id()==ID_unsignedbv || type.id()==ID_signedbv || type.id()==ID_floatbv || type.id()==ID_fixedbv || type.id()==ID_pointer || type.id()==ID_bv) width=string2integer(type.get_string(ID_width)); else width=pointer_offset_size(type, ns)*8; if(width>=0) { std::string result; for(; width!=0; --width) result+='x'; return result; } return ""; }
bool value_set_dereferencet::memory_model_bytes( exprt &value, const typet &to_type, const guardt &guard, const exprt &offset) { const typet from_type=value.type(); // We simply refuse to convert to/from code. if(from_type.id()==ID_code || to_type.id()==ID_code) return false; // We won't do this without a commitment to an endianness. if(config.ansi_c.endianness==configt::ansi_ct::endiannesst::NO_ENDIANNESS) return false; // But everything else we will try! // We just rely on byte_extract to do the job! exprt result; // See if we have an array of bytes already, // and we want something byte-sized. if(ns.follow(from_type).id()==ID_array && pointer_offset_size(ns.follow(from_type).subtype(), ns)==1 && pointer_offset_size(to_type, ns)==1 && is_a_bv_type(ns.follow(from_type).subtype()) && is_a_bv_type(to_type)) { // yes, can use 'index' result=index_exprt(value, offset, ns.follow(from_type).subtype()); // possibly need to convert if(!base_type_eq(result.type(), to_type, ns)) result.make_typecast(to_type); } else { // no, use 'byte_extract' result=exprt(byte_extract_id(), to_type); result.copy_to_operands(value, offset); } value=result; // are we within the bounds? if(options.get_bool_option("pointer-check")) { // upper bound { exprt from_width=size_of_expr(from_type, ns); INVARIANT( from_width.is_not_nil(), "unknown or invalid type size:\n"+from_type.pretty()); exprt to_width= to_type.id()==ID_empty? from_integer(0, size_type()):size_of_expr(to_type, ns); INVARIANT( to_width.is_not_nil(), "unknown or invalid type size:\n"+to_type.pretty()); INVARIANT( from_width.type()==to_width.type(), "type mismatch on result of size_of_expr"); minus_exprt bound(from_width, to_width); if(bound.type()!=offset.type()) bound.make_typecast(offset.type()); binary_relation_exprt offset_upper_bound(offset, ID_gt, bound); guardt tmp_guard(guard); tmp_guard.add(offset_upper_bound); dereference_callback.dereference_failure( "pointer dereference", "object upper bound", tmp_guard); } // lower bound is easy if(!offset.is_zero()) { binary_relation_exprt offset_lower_bound( offset, ID_lt, from_integer(0, offset.type())); guardt tmp_guard(guard); tmp_guard.add(offset_lower_bound); dereference_callback.dereference_failure( "pointer dereference", "object lower bound", tmp_guard); } } return true; }