exprt dereferencet::dereference_plus( const exprt &expr, const exprt &offset, const typet &type) { if(expr.operands().size()>2) return dereference_rec(make_binary(expr), offset, type); // binary exprt pointer=expr.op0(), integer=expr.op1(); if(ns.follow(integer.type()).id()==ID_pointer) std::swap(pointer, integer); // multiply integer by object size exprt size=size_of_expr(pointer.type().subtype(), ns); if(size.is_nil()) throw "dereference failed to get object size for pointer arithmetic"; // make types of offset and size match if(size.type()!=integer.type()) integer.make_typecast(size.type()); exprt new_offset=plus_exprt(offset, mult_exprt(size, integer)); return dereference_rec(pointer, new_offset, type); }
static void build_object_descriptor_rec( const namespacet &ns, const exprt &expr, object_descriptor_exprt &dest) { const signedbv_typet index_type(config.ansi_c.pointer_width); if(expr.id()==ID_index) { const index_exprt &index=to_index_expr(expr); build_object_descriptor_rec(ns, index.array(), dest); exprt sub_size=size_of_expr(expr.type(), ns); assert(sub_size.is_not_nil()); dest.offset()= plus_exprt(dest.offset(), mult_exprt(typecast_exprt(index.index(), index_type), typecast_exprt(sub_size, index_type))); } else if(expr.id()==ID_member) { const member_exprt &member=to_member_expr(expr); const exprt &struct_op=member.struct_op(); build_object_descriptor_rec(ns, struct_op, dest); exprt offset=member_offset_expr(member, ns); assert(offset.is_not_nil()); dest.offset()= plus_exprt(dest.offset(), typecast_exprt(offset, index_type)); } else if(expr.id()==ID_byte_extract_little_endian || expr.id()==ID_byte_extract_big_endian) { const byte_extract_exprt &be=to_byte_extract_expr(expr); dest.object()=be.op(); build_object_descriptor_rec(ns, be.op(), dest); dest.offset()= plus_exprt(dest.offset(), typecast_exprt(to_byte_extract_expr(expr).offset(), index_type)); } else if(expr.id()==ID_typecast) { const typecast_exprt &tc=to_typecast_expr(expr); dest.object()=tc.op(); build_object_descriptor_rec(ns, tc.op(), dest); } }
void goto_convertt::do_java_new( const exprt &lhs, const side_effect_exprt &rhs, goto_programt &dest) { if(lhs.is_nil()) throw "do_java_new without lhs is yet to be implemented"; source_locationt location=rhs.source_location(); assert(rhs.operands().empty()); if(rhs.type().id()!=ID_pointer) throw "do_java_new returns pointer"; typet object_type=rhs.type().subtype(); // build size expression exprt object_size=size_of_expr(object_type, ns); if(object_size.is_nil()) throw "do_java_new got nil object_size"; // we produce a malloc side-effect, which stays side_effect_exprt malloc_expr(ID_malloc); malloc_expr.copy_to_operands(object_size); malloc_expr.type()=pointer_typet(object_type); goto_programt::targett t_n=dest.add_instruction(ASSIGN); t_n->code=code_assignt(lhs, malloc_expr); t_n->source_location=location; // zero-initialize the object dereference_exprt deref(lhs, object_type); exprt zero_object=zero_initializer(object_type, location, ns, get_message_handler()); set_class_identifier(to_struct_expr(zero_object), ns, to_symbol_type(object_type)); goto_programt::targett t_i=dest.add_instruction(ASSIGN); t_i->code=code_assignt(deref, zero_object); t_i->source_location=location; }
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; }
value_set_dereferencet::valuet value_set_dereferencet::build_reference_to( const exprt &what, const modet mode, const exprt &pointer_expr, const guardt &guard) { const typet &dereference_type= ns.follow(pointer_expr.type()).subtype(); if(what.id()==ID_unknown || what.id()==ID_invalid) { invalid_pointer(pointer_expr, guard); return valuet(); } if(what.id()!=ID_object_descriptor) throw "unknown points-to: "+what.id_string(); const object_descriptor_exprt &o=to_object_descriptor_expr(what); const exprt &root_object=o.root_object(); const exprt &object=o.object(); #if 0 std::cout << "O: " << from_expr(ns, "", root_object) << '\n'; #endif valuet result; if(root_object.id()=="NULL-object") { if(options.get_bool_option("pointer-check")) { guardt tmp_guard(guard); if(o.offset().is_zero()) { tmp_guard.add(null_pointer(pointer_expr)); dereference_callback.dereference_failure( "pointer dereference", "NULL pointer", tmp_guard); } else { tmp_guard.add(null_object(pointer_expr)); dereference_callback.dereference_failure( "pointer dereference", "NULL plus offset pointer", tmp_guard); } } } else if(root_object.id()==ID_dynamic_object) { // const dynamic_object_exprt &dynamic_object= // to_dynamic_object_expr(root_object); // the object produced by malloc exprt malloc_object= ns.lookup(CPROVER_PREFIX "malloc_object").symbol_expr(); exprt is_malloc_object=same_object(pointer_expr, malloc_object); // constraint that it actually is a dynamic object exprt dynamic_object_expr(ID_dynamic_object, bool_typet()); dynamic_object_expr.copy_to_operands(pointer_expr); // this is also our guard result.pointer_guard=dynamic_object_expr; // can't remove here, turn into *p result.value=dereference_exprt(pointer_expr, dereference_type); if(options.get_bool_option("pointer-check")) { // if(!dynamic_object.valid().is_true()) { // check if it is still alive guardt tmp_guard(guard); tmp_guard.add(deallocated(pointer_expr, ns)); dereference_callback.dereference_failure( "pointer dereference", "dynamic object deallocated", tmp_guard); } if(options.get_bool_option("bounds-check")) { if(!o.offset().is_zero()) { // check lower bound guardt tmp_guard(guard); tmp_guard.add(is_malloc_object); tmp_guard.add( dynamic_object_lower_bound( pointer_expr, ns, nil_exprt())); dereference_callback.dereference_failure( "pointer dereference", "dynamic object lower bound", tmp_guard); } { // check upper bound // we check SAME_OBJECT(__CPROVER_malloc_object, p) && // POINTER_OFFSET(p)+size>__CPROVER_malloc_size guardt tmp_guard(guard); tmp_guard.add(is_malloc_object); tmp_guard.add( dynamic_object_upper_bound( pointer_expr, dereference_type, ns, size_of_expr(dereference_type, ns))); dereference_callback.dereference_failure( "pointer dereference", "dynamic object upper bound", tmp_guard); } } } } else if(root_object.id()==ID_integer_address) { // This is stuff like *((char *)5). // This is turned into an access to __CPROVER_memory[...]. if(language_mode==ID_java) { result.value=nil_exprt(); return result; } const symbolt &memory_symbol=ns.lookup(CPROVER_PREFIX "memory"); exprt symbol_expr=symbol_exprt(memory_symbol.name, memory_symbol.type); if(base_type_eq( ns.follow(memory_symbol.type).subtype(), dereference_type, ns)) { // Types match already, what a coincidence! // We can use an index expression. exprt index_expr=index_exprt(symbol_expr, pointer_offset(pointer_expr)); index_expr.type()=ns.follow(memory_symbol.type).subtype(); result.value=index_expr; } else if(dereference_type_compare( ns.follow(memory_symbol.type).subtype(), dereference_type)) { exprt index_expr=index_exprt(symbol_expr, pointer_offset(pointer_expr)); index_expr.type()=ns.follow(memory_symbol.type).subtype(); result.value=typecast_exprt(index_expr, dereference_type); } else { // We need to use byte_extract. // Won't do this without a commitment to an endianness. if(config.ansi_c.endianness==configt::ansi_ct::endiannesst::NO_ENDIANNESS) { } else { exprt byte_extract(byte_extract_id(), dereference_type); byte_extract.copy_to_operands( symbol_expr, pointer_offset(pointer_expr)); result.value=byte_extract; } } } else { // something generic -- really has to be a symbol address_of_exprt object_pointer(object); if(o.offset().is_zero()) { equal_exprt equality(pointer_expr, object_pointer); if(ns.follow(equality.lhs().type())!=ns.follow(equality.rhs().type())) equality.lhs().make_typecast(equality.rhs().type()); result.pointer_guard=equality; } else { result.pointer_guard=same_object(pointer_expr, object_pointer); } guardt tmp_guard(guard); tmp_guard.add(result.pointer_guard); valid_check(object, tmp_guard, mode); const typet &object_type=ns.follow(object.type()); const exprt &root_object=o.root_object(); const typet &root_object_type=ns.follow(root_object.type()); exprt root_object_subexpression=root_object; if(dereference_type_compare(object_type, dereference_type) && o.offset().is_zero()) { // The simplest case: types match, and offset is zero! // This is great, we are almost done. result.value=object; if(object_type!=ns.follow(dereference_type)) result.value.make_typecast(dereference_type); } else if(root_object_type.id()==ID_array && dereference_type_compare( root_object_type.subtype(), dereference_type)) { // We have an array with a subtype that matches // the dereferencing type. // We will require well-alignedness! exprt offset; // this should work as the object is essentially the root object if(o.offset().is_constant()) offset=o.offset(); else offset=pointer_offset(pointer_expr); exprt adjusted_offset; // are we doing a byte? mp_integer element_size= dereference_type.id()==ID_empty? pointer_offset_size(char_type(), ns): pointer_offset_size(dereference_type, ns); if(element_size==1) { // no need to adjust offset adjusted_offset=offset; } else if(element_size<=0) { throw "unknown or invalid type size of:\n"+dereference_type.pretty(); } else { exprt element_size_expr= from_integer(element_size, offset.type()); adjusted_offset=binary_exprt( offset, ID_div, element_size_expr, offset.type()); // TODO: need to assert well-alignedness } index_exprt index_expr= index_exprt(root_object, adjusted_offset, root_object_type.subtype()); bounds_check(index_expr, tmp_guard); result.value=index_expr; if(ns.follow(result.value.type())!=ns.follow(dereference_type)) result.value.make_typecast(dereference_type); } else if(get_subexpression_at_offset( root_object_subexpression, o.offset(), dereference_type, ns)) { // Successfully found a member, array index, or combination thereof // that matches the desired type and offset: result.value=root_object_subexpression; } else { // we extract something from the root object result.value=o.root_object(); // this is relative to the root object const exprt offset=pointer_offset(pointer_expr); if(memory_model(result.value, dereference_type, tmp_guard, offset)) { // ok, done } else { if(options.get_bool_option("pointer-check")) { std::string msg="memory model not applicable (got `"; msg+=from_type(ns, "", result.value.type()); msg+="', expected `"; msg+=from_type(ns, "", dereference_type); msg+="')"; dereference_callback.dereference_failure( "pointer dereference", msg, tmp_guard); } return valuet(); // give up, no way that this is ok } } } return result; }
void goto_convertt::do_java_new_array( const exprt &lhs, const side_effect_exprt &rhs, goto_programt &dest) { if(lhs.is_nil()) throw "do_java_new_array without lhs is yet to be implemented"; source_locationt location=rhs.source_location(); assert(rhs.operands().size()>=1); // one per dimension if(rhs.type().id()!=ID_pointer) throw "do_java_new_array returns pointer"; typet object_type=rhs.type().subtype(); // build size expression exprt object_size=size_of_expr(object_type, ns); if(object_size.is_nil()) throw "do_java_new_array got nil object_size"; // we produce a malloc side-effect, which stays side_effect_exprt malloc_expr(ID_malloc); malloc_expr.copy_to_operands(object_size); malloc_expr.type()=pointer_typet(object_type); goto_programt::targett t_n=dest.add_instruction(ASSIGN); t_n->code=code_assignt(lhs, malloc_expr); t_n->source_location=location; // multi-dimensional? assert(ns.follow(object_type).id()==ID_struct); const struct_typet &struct_type=to_struct_type(ns.follow(object_type)); assert(struct_type.components().size()==3); // if it's an array, we need to set the length field dereference_exprt deref(lhs, object_type); member_exprt length(deref, struct_type.components()[1].get_name(), struct_type.components()[1].type()); goto_programt::targett t_s=dest.add_instruction(ASSIGN); t_s->code=code_assignt(length, rhs.op0()); t_s->source_location=location; // we also need to allocate space for the data member_exprt data(deref, struct_type.components()[2].get_name(), struct_type.components()[2].type()); side_effect_exprt data_cpp_new_expr(ID_cpp_new_array, data.type()); data_cpp_new_expr.set(ID_size, rhs.op0()); goto_programt::targett t_p=dest.add_instruction(ASSIGN); t_p->code=code_assignt(data, data_cpp_new_expr); t_p->source_location=location; // zero-initialize the data exprt zero_element=gen_zero(data.type().subtype()); codet array_set(ID_array_set); array_set.copy_to_operands(data, zero_element); goto_programt::targett t_d=dest.add_instruction(OTHER); t_d->code=array_set; t_d->source_location=location; if(rhs.operands().size()>=2) { // produce // for(int i=0; i<size; i++) tmp[i]=java_new(dim-1); // This will be converted recursively. goto_programt tmp; symbol_exprt tmp_i= new_tmp_symbol(index_type(), "index", tmp, location).symbol_expr(); code_fort for_loop; side_effect_exprt sub_java_new=rhs; sub_java_new.operands().erase(sub_java_new.operands().begin()); side_effect_exprt inc(ID_assign); inc.operands().resize(2); inc.op0()=tmp_i; inc.op1()=plus_exprt(tmp_i, gen_one(tmp_i.type())); dereference_exprt deref_expr(plus_exprt(data, tmp_i), data.type().subtype()); for_loop.init()=code_assignt(tmp_i, gen_zero(tmp_i.type())); for_loop.cond()=binary_relation_exprt(tmp_i, ID_lt, rhs.op0()); for_loop.iter()=inc; for_loop.body()=code_skipt(); for_loop.body()=code_assignt(deref_expr, sub_java_new); convert(for_loop, tmp); dest.destructive_append(tmp); } }
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); }