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); bool found_functions; const exprt &pointer=function.op0(); remove_const_function_pointerst::functionst functions; does_remove_constt const_removal_check(goto_program, ns); if(const_removal_check()) { warning() << "Cast from const to non-const pointer found, only worst case" << " function pointer removal will be done." << eom; found_functions=false; } else { remove_const_function_pointerst fpr( get_message_handler(), pointer, ns, symbol_table); found_functions=fpr(functions); // Either found_functions is true therefore the functions should not // be empty // Or found_functions is false therefore the functions should be empty assert(found_functions != functions.empty()); if(functions.size()==1) { to_code_function_call(target->code).function()=*functions.cbegin(); return; } } if(!found_functions) { if(only_resolve_const_fps) { // If this mode is enabled, we only remove function pointers // that we can resolve either to an exact funciton, or an exact subset // (e.g. a variable index in a constant array). // Since we haven't found functions, we would now resort to // replacing the function pointer with any function with a valid signature // Since we don't want to do that, we abort. return; } bool return_value_used=code.lhs().is_not_nil(); // get all type-compatible functions // whose address is ever taken for(const auto &t : type_map) { // address taken? if(address_taken.find(t.first)==address_taken.end()) continue; // type-compatible? if(!is_type_compatible(return_value_used, call_type, t.second)) continue; if(t.first=="pthread_mutex_cleanup") continue; symbol_exprt expr; expr.type()=t.second; expr.set_identifier(t.first); functions.insert(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(const auto &fun : functions) { // call function goto_programt::targett t1=new_code_calls.add_instruction(); t1->make_function_call(code); to_code_function_call(t1->code).function()=fun; // 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()=fun; address_of.type()=pointer_typet(); address_of.type().subtype()=fun.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); }
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); }