exprt dereferencet::dereference_typecast( const typecast_exprt &expr, const exprt &offset, const typet &type) { const exprt &op=expr.op(); const typet &op_type=ns.follow(op.type()); // pointer type cast? if(op_type.id()==ID_pointer) return dereference_rec(op, offset, type); // just pass down else if(op_type.id()==ID_signedbv || op_type.id()==ID_unsignedbv) { // We got an integer-typed address A. We turn this back (!) // into *(type *)(A+offset), and then let some other layer // worry about it. exprt integer=op; if(!offset.is_zero()) integer= plus_exprt(offset, typecast_exprt(op, offset.type())); exprt new_typecast= typecast_exprt(integer, pointer_typet(type)); return dereference_exprt(new_typecast, type); } else throw "dereferencet: unexpected cast"; }
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; }
void c_typecastt::implicit_typecast_followed( exprt &expr, const typet &src_type, const typet &dest_type) { if(dest_type.id()==ID_union) // do transparent union if(dest_type.id()==ID_union && dest_type.get_bool(ID_C_transparent_union) && src_type.id()!=ID_union) { // The argument corresponding to a transparent union type can be of any // type in the union; no explicit cast is required. // Check union members. const union_typet &dest_union_type=to_union_type(dest_type); for(union_typet::componentst::const_iterator it=dest_union_type.components().begin(); it!=dest_union_type.components().end(); it++) { if(!check_c_implicit_typecast(src_type, it->type())) { // build union constructor exprt union_expr(ID_union, dest_union_type); union_expr.move_to_operands(expr); union_expr.set(ID_component_name, it->get_name()); expr=union_expr; return; // ok } } } if(dest_type.id()==ID_pointer) { // special case: 0 == NULL if(expr.is_zero() && ( src_type.id()==ID_unsignedbv || src_type.id()==ID_signedbv || src_type.id()==ID_natural || src_type.id()==ID_integer)) { expr=exprt(ID_constant, dest_type); expr.set(ID_value, ID_NULL); return; // ok } if(src_type.id()==ID_pointer || src_type.id()==ID_array) { // we are quite generous about pointers const typet &src_sub=ns.follow(src_type.subtype()); const typet &dest_sub=ns.follow(dest_type.subtype()); if(is_void_pointer(src_type) || is_void_pointer(dest_type)) { // from/to void is always good } else if(src_sub.id()==ID_code && dest_sub.id()==ID_code) { // very generous: // between any two function pointers it's ok } else if(base_type_eq(src_type.subtype(), dest_type.subtype(), ns)) { // ok } else if((is_number(src_sub) || src_sub.id()==ID_c_enum) && (is_number(dest_sub) || dest_sub.id()==ID_c_enum)) { // Also generous: between any to scalar types it's ok. // We should probably check the size. } else warnings.push_back("incompatible pointer types"); // check qualifiers /* if(src_type.subtype().get_bool(ID_C_constant) && !dest_type.subtype().get_bool(ID_C_constant)) warnings.push_back("disregarding const"); */ if(src_type.subtype().get_bool(ID_C_volatile) && !dest_type.subtype().get_bool(ID_C_volatile)) warnings.push_back("disregarding volatile"); if(src_type==dest_type) { expr.type()=src_type; // because of qualifiers } else do_typecast(expr, dest_type); return; // ok } } if(check_c_implicit_typecast(src_type, dest_type)) errors.push_back("implicit conversion not permitted"); else if(src_type!=dest_type) do_typecast(expr, dest_type); }