Skip to content

Commit 1dbc443

Browse files
committed
Remove function pointers slightly more precisely
Scans the goto program for assigns to function pointers and builds a map of assigns to those function pointers. Then uses only these functions to replace the function pointer with. If a function pointer is ever written to with anything more complicated than a straight forward address_of a function, defaults to normal behaviour. Only works for: - standalone function pointers - function pointers that are 1 level deep in a struct Current unsound-ness to be fixed: - if a function pointer is part of a struct, and the struct is assigned to in total, this is not detected.
1 parent a354513 commit 1dbc443

File tree

1 file changed

+134
-4
lines changed

1 file changed

+134
-4
lines changed

src/goto-programs/remove_function_pointers.cpp

Lines changed: 134 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ Author: Daniel Kroening, [email protected]
3030
#include "compute_called_functions.h"
3131
#include "remove_const_function_pointers.h"
3232

33+
#include <iostream>
34+
35+
#define UNKNOWN_ASSIGN "##unknown##"
36+
3337
class remove_function_pointerst:public messaget
3438
{
3539
public:
@@ -48,6 +52,12 @@ class remove_function_pointerst:public messaget
4852
const namespacet ns;
4953
symbol_tablet &symbol_table;
5054
bool add_safety_assertion;
55+
std::map<irep_idt, std::unordered_set<irep_idt>> function_pointer_map;
56+
std::size_t number_of_function_pointers_replaced;
57+
std::size_t max_size_of_case_split;
58+
std::size_t total_number_of_replacement_candidates;
59+
60+
5161

5262
// We can optionally halt the FP removal if we aren't able to use
5363
// remove_const_function_pointerst to successfully narrow to a small
@@ -80,6 +90,13 @@ class remove_function_pointerst:public messaget
8090
code_function_callt &function_call,
8191
goto_programt &dest);
8292

93+
/// scans through goto functions and builds a map of function
94+
/// pointers to a set of functions that have been written to each pointer,
95+
/// stored as irep_idts.
96+
/// The map is stored as variable in remove_function_pointerst
97+
/// \param goto_functions goto functions to scan through
98+
void get_all_writes_to_pointers(goto_functionst &goto_functions);
99+
83100
void
84101
compute_address_taken_in_symbols(std::unordered_set<irep_idt> &address_taken)
85102
{
@@ -90,6 +107,12 @@ class remove_function_pointerst:public messaget
90107
}
91108
};
92109

110+
static irep_idt get_member_identifier(const member_exprt &member)
111+
{
112+
return id2string(member.symbol().get_identifier()) +
113+
id2string(member.get_component_name());
114+
}
115+
93116
remove_function_pointerst::remove_function_pointerst(
94117
message_handlert &_message_handler,
95118
symbol_tablet &_symbol_table,
@@ -99,6 +122,9 @@ remove_function_pointerst::remove_function_pointerst(
99122
ns(_symbol_table),
100123
symbol_table(_symbol_table),
101124
add_safety_assertion(_add_safety_assertion),
125+
number_of_function_pointers_replaced(0u),
126+
max_size_of_case_split(0u),
127+
total_number_of_replacement_candidates(0u),
102128
only_resolve_const_fps(only_resolve_const_fps)
103129
{
104130
compute_address_taken_in_symbols(address_taken);
@@ -255,6 +281,7 @@ void remove_function_pointerst::fix_return_type(
255281
old_lhs, typecast_exprt(tmp_symbol_expr, old_lhs.type()));
256282
}
257283

284+
258285
void remove_function_pointerst::remove_function_pointer(
259286
goto_programt &goto_program,
260287
goto_programt::targett target)
@@ -348,6 +375,41 @@ void remove_function_pointerst::remove_function_pointer(
348375
}
349376
}
350377

378+
// we only handle cases where the LHS is a symbol or a member of a struct
379+
if(pointer.id() == ID_symbol || pointer.id() == ID_member)
380+
{
381+
irep_idt identifier;
382+
if(pointer.id() == ID_symbol)
383+
identifier =
384+
to_symbol_expr(to_dereference_expr(code.function()).pointer())
385+
.get_identifier();
386+
else
387+
{
388+
identifier = get_member_identifier(to_member_expr(pointer));
389+
}
390+
391+
if(function_pointer_map.find(identifier) != function_pointer_map.end())
392+
{
393+
status() << "Replacing function pointer from map of possible assigns\n";
394+
if(
395+
function_pointer_map[identifier].find(UNKNOWN_ASSIGN) ==
396+
function_pointer_map[identifier].end())
397+
{
398+
for(auto func_itr = functions.begin(); func_itr != functions.end();)
399+
{
400+
if(
401+
function_pointer_map[identifier].find(func_itr->get_identifier()) ==
402+
function_pointer_map[identifier].end())
403+
{
404+
func_itr = functions.erase(func_itr);
405+
}
406+
else
407+
func_itr++;
408+
}
409+
}
410+
}
411+
}
412+
351413
// the final target is a skip
352414
goto_programt final_skip;
353415

@@ -430,6 +492,10 @@ void remove_function_pointerst::remove_function_pointer(
430492
statistics().source_location=target->source_location;
431493
statistics() << "replacing function pointer by "
432494
<< functions.size() << " possible targets" << eom;
495+
number_of_function_pointers_replaced++;
496+
total_number_of_replacement_candidates+=functions.size();
497+
if(functions.size()>max_size_of_case_split)
498+
max_size_of_case_split = functions.size();
433499

434500
// list the names of functions when verbosity is at debug level
435501
conditional_output(
@@ -451,6 +517,7 @@ void remove_function_pointerst::remove_function_pointer(
451517
});
452518
}
453519

520+
454521
bool remove_function_pointerst::remove_function_pointers(
455522
goto_programt &goto_program)
456523
{
@@ -459,13 +526,12 @@ bool remove_function_pointerst::remove_function_pointers(
459526
Forall_goto_program_instructions(target, goto_program)
460527
if(target->is_function_call())
461528
{
462-
const code_function_callt &code=
463-
to_code_function_call(target->code);
529+
const code_function_callt &code = to_code_function_call(target->code);
464530

465-
if(code.function().id()==ID_dereference)
531+
if(code.function().id() == ID_dereference)
466532
{
467533
remove_function_pointer(goto_program, target);
468-
did_something=true;
534+
did_something = true;
469535
}
470536
}
471537

@@ -475,8 +541,10 @@ bool remove_function_pointerst::remove_function_pointers(
475541
return did_something;
476542
}
477543

544+
478545
void remove_function_pointerst::operator()(goto_functionst &functions)
479546
{
547+
get_all_writes_to_pointers(functions);
480548
bool did_something=false;
481549

482550
for(goto_functionst::function_mapt::iterator f_it=
@@ -490,8 +558,23 @@ void remove_function_pointerst::operator()(goto_functionst &functions)
490558
did_something=true;
491559
}
492560

561+
493562
if(did_something)
563+
{
494564
functions.compute_location_numbers();
565+
566+
std::cout << "Statistics:\n"
567+
<< "Replaced " << number_of_function_pointers_replaced
568+
<< " function pointers "
569+
<< " with " << total_number_of_replacement_candidates
570+
<< " possible candidate functions. \n"
571+
<< "Max number of candidates in a single replacement: "
572+
<< max_size_of_case_split << "\n"
573+
<< "Mean number of candidates in a single replacement: "
574+
<< total_number_of_replacement_candidates /
575+
number_of_function_pointers_replaced
576+
<< "\n";
577+
}
495578
}
496579

497580
bool remove_function_pointers(message_handlert &_message_handler,
@@ -535,10 +618,57 @@ void remove_function_pointers(message_handlert &_message_handler,
535618
bool add_safety_assertion,
536619
bool only_remove_const_fps)
537620
{
621+
538622
remove_function_pointers(
539623
_message_handler,
540624
goto_model.symbol_table,
541625
goto_model.goto_functions,
542626
add_safety_assertion,
543627
only_remove_const_fps);
544628
}
629+
630+
void remove_function_pointerst::get_all_writes_to_pointers(
631+
goto_functionst &goto_functions)
632+
{
633+
for(goto_functionst::function_mapt::iterator f_it =
634+
goto_functions.function_map.begin();
635+
f_it != goto_functions.function_map.end();
636+
f_it++)
637+
{
638+
goto_programt &goto_program = f_it->second.body;
639+
Forall_goto_program_instructions(target, goto_program)
640+
{
641+
if(!target->is_assign())
642+
continue;
643+
644+
const code_assignt &code_assign = to_code_assign(target->code);
645+
const auto &lhs = code_assign.lhs();
646+
const auto &rhs = code_assign.rhs();
647+
648+
if(lhs.type().id() == ID_pointer && lhs.type().subtype().id() == ID_code)
649+
{
650+
irep_idt lhs_irep;
651+
if(lhs.id() == ID_symbol)
652+
lhs_irep = to_symbol_expr(lhs).get_identifier();
653+
else if(lhs.id() == ID_member)
654+
{
655+
lhs_irep = get_member_identifier(to_member_expr(lhs));
656+
}
657+
else
658+
continue;
659+
660+
if(rhs.id() == ID_address_of && rhs.type().subtype().id() == ID_code)
661+
{
662+
irep_idt rhs_irep =
663+
to_symbol_expr(to_address_of_expr(rhs).object()).get_identifier();
664+
if(function_pointer_map.find(lhs_irep) != function_pointer_map.end())
665+
(function_pointer_map[lhs_irep]).insert(rhs_irep);
666+
else
667+
function_pointer_map[lhs_irep] = {{rhs_irep}};
668+
}
669+
else
670+
function_pointer_map[lhs_irep] = {{UNKNOWN_ASSIGN}};
671+
}
672+
}
673+
}
674+
}

0 commit comments

Comments
 (0)