void remove_function_pointerst::remove_function_pointer( goto_programt &goto_program, goto_programt::targett target) { const code_function_callt &code= to_code_function_call(target->code); const exprt &function=code.function(); // this better have the right type const code_typet &call_type=to_code_type(function.type()); assert(function.id()==ID_dereference); assert(function.operands().size()==1); const exprt &pointer=function.op0(); typedef std::list<exprt> functionst; functionst functions; // get all type-compatible functions // whose address is ever taken for(type_mapt::const_iterator f_it= type_map.begin(); f_it!=type_map.end(); f_it++) { // address taken? if(address_taken.find(f_it->first)==address_taken.end()) continue; // type-compatible? if(!is_type_compatible(call_type, f_it->second)) continue; symbol_exprt expr; expr.type()=f_it->second; expr.set_identifier(f_it->first); functions.push_back(expr); } // 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; // the signature of the function might not match precisely fix_argument_types(to_code_function_call(t1->code)); fix_return_type(to_code_function_call(t1->code), new_code_calls); // goto final goto_programt::targett t3=new_code_calls.add_instruction(); t3->make_goto(t_final, true_exprt()); // goto to call address_of_exprt address_of; address_of.object()=*it; address_of.type()=pointer_typet(); address_of.type().subtype()=it->type(); if(address_of.type()!=pointer.type()) address_of.make_typecast(pointer.type()); goto_programt::targett t4=new_code_gotos.add_instruction(); t4->make_goto(t1, equal_exprt(pointer, address_of)); } // fall-through if(add_safety_assertion) { goto_programt::targett t=new_code_gotos.add_instruction(); t->make_assertion(false_exprt()); t->location.set(ID_property, "pointer dereference"); t->location.set(ID_comment, "invalid function pointer"); } 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=it->location.get_property(); irep_idt comment=it->location.get_comment(); it->location=target->location; it->function=target->function; if(!property.empty()) it->location.set_property(property); if(!comment.empty()) it->location.set_comment(comment); }
void remove_function_pointerst::remove_function_pointer( goto_programt &goto_program, goto_programt::targett target) { const code_function_callt &code= to_code_function_call(target->code); const exprt &function=code.function(); // this better have the right type code_typet call_type=to_code_type(function.type()); // refine the type in case the forward declaration was incomplete if(call_type.has_ellipsis() && call_type.parameters().empty()) { call_type.remove_ellipsis(); forall_expr(it, code.arguments()) call_type.parameters().push_back( code_typet::parametert(it->type())); } assert(function.id()==ID_dereference); assert(function.operands().size()==1); const exprt &pointer=function.op0(); // Is this simple? if(pointer.id()==ID_address_of && to_address_of_expr(pointer).object().id()==ID_symbol) { to_code_function_call(target->code).function()= to_address_of_expr(pointer).object(); return; } typedef std::list<exprt> functionst; functionst functions; bool return_value_used=code.lhs().is_not_nil(); // get all type-compatible functions // whose address is ever taken for(type_mapt::const_iterator f_it= type_map.begin(); f_it!=type_map.end(); f_it++) { // address taken? if(address_taken.find(f_it->first)==address_taken.end()) continue; // type-compatible? if(!is_type_compatible(return_value_used, call_type, f_it->second)) continue; if(f_it->first=="pthread_mutex_cleanup") continue; symbol_exprt expr; expr.type()=f_it->second; expr.set_identifier(f_it->first); functions.push_back(expr); } // 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; // the signature of the function might not match precisely fix_argument_types(to_code_function_call(t1->code)); fix_return_type(to_code_function_call(t1->code), new_code_calls); // goto final goto_programt::targett t3=new_code_calls.add_instruction(); t3->make_goto(t_final, true_exprt()); // goto to call address_of_exprt address_of; address_of.object()=*it; address_of.type()=pointer_typet(); address_of.type().subtype()=it->type(); if(address_of.type()!=pointer.type()) address_of.make_typecast(pointer.type()); goto_programt::targett t4=new_code_gotos.add_instruction(); t4->make_goto(t1, equal_exprt(pointer, address_of)); } // fall-through if(add_safety_assertion) { goto_programt::targett t=new_code_gotos.add_instruction(); t->make_assertion(false_exprt()); t->source_location.set_property_class("pointer dereference"); t->source_location.set_comment("invalid function pointer"); } 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); }