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"; }
dereference_exprt cegis_operand(const symbol_tablet &st, const std::string &func_name, const typet &type, const size_t op) { const member_exprt operand_id(cegis_operand_id(st, func_name, op)); const std::string array_name(cegis_operand_array_name(st, type)); const symbol_exprt array(st.lookup(array_name).symbol_expr()); return dereference_exprt(index_exprt(array, operand_id), type); }
/// Turns union.member into *((T *)(&union)), where T is the type of the member. /// This is semantics-preserving for unions, but requires some elaboration in /// case the union member is an array. void translate_union_member(exprt &dest, const namespacet &ns) { #if 0 if(dest.id()==ID_member) { // TODO } address_of_exprt address_of_expr(member_expr.struct_op()); pointer_typet pointer_type(member_expr.type()); typecast_exprt typecast_expr(address_of_expr, pointer_type); return dereference_exprt(typecast_expr, member_expr.type()); #endif }
void remove_virtual_functionst::remove_virtual_function( goto_programt &goto_program, goto_programt::targett target) { const code_function_callt &code= to_code_function_call(target->code); const exprt &function=code.function(); assert(function.id()==ID_virtual_function); assert(!code.arguments().empty()); functionst functions; get_functions(function, functions); if(functions.empty()) { target->make_skip(); return; // give up } // the final target is a skip goto_programt final_skip; goto_programt::targett t_final=final_skip.add_instruction(); t_final->make_skip(); // build the calls and gotos goto_programt new_code_calls; goto_programt new_code_gotos; for(functionst::const_iterator it=functions.begin(); it!=functions.end(); it++) { // call function goto_programt::targett t1=new_code_calls.add_instruction(); t1->make_function_call(code); to_code_function_call(t1->code).function()=it->symbol_expr; // goto final goto_programt::targett t3=new_code_calls.add_instruction(); t3->make_goto(t_final, true_exprt()); exprt this_expr=code.arguments()[0]; if(this_expr.type().id()!=ID_pointer || this_expr.type().id()!=ID_struct) { symbol_typet symbol_type(it->class_id); this_expr=typecast_exprt(this_expr, pointer_typet(symbol_type)); } exprt deref=dereference_exprt(this_expr, this_expr.type().subtype()); exprt c_id1=constant_exprt(it->class_id, string_typet()); exprt c_id2=build_class_identifier(deref); goto_programt::targett t4=new_code_gotos.add_instruction(); t4->make_goto(t1, equal_exprt(c_id1, c_id2)); } goto_programt new_code; // patch them all together new_code.destructive_append(new_code_gotos); new_code.destructive_append(new_code_calls); new_code.destructive_append(final_skip); // set locations Forall_goto_program_instructions(it, new_code) { irep_idt property_class=it->source_location.get_property_class(); irep_idt comment=it->source_location.get_comment(); it->source_location=target->source_location; it->function=target->function; if(!property_class.empty()) it->source_location.set_property_class(property_class); if(!comment.empty()) it->source_location.set_comment(comment); }
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_scanf( const exprt &lhs, const exprt &function, const exprt::operandst &arguments, goto_programt &dest) { const irep_idt &f_id=function.get(ID_identifier); if(f_id==CPROVER_PREFIX "scanf") { if(arguments.size()<1) { err_location(function); error() << "scanf takes at least one argument" << eom; throw 0; } irep_idt format_string; if(!get_string_constant(arguments[0], format_string)) { // use our model format_token_listt token_list=parse_format_string(id2string(format_string)); std::size_t argument_number=1; for(const auto & t : token_list) { typet type=get_type(t); if(type.is_not_nil()) { if(argument_number<arguments.size()) { exprt ptr= typecast_exprt(arguments[argument_number], pointer_type(type)); argument_number++; // make it nondet for now exprt lhs=dereference_exprt(ptr, type); exprt rhs=side_effect_expr_nondett(type); code_assignt assign(lhs, rhs); assign.add_source_location()=function.source_location(); copy(assign, ASSIGN, dest); } } } } else { // we'll just do nothing code_function_callt function_call; function_call.lhs()=lhs; function_call.function()=function; function_call.arguments()=arguments; function_call.add_source_location()=function.source_location(); copy(function_call, FUNCTION_CALL, dest); } } else assert(false); }
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; }