1919#include < util/pointer_offset_size.h>
2020#include < util/source_location.h>
2121#include < util/std_expr.h>
22+ #include < util/string_utils.h>
2223
2324#include < analyses/does_remove_const.h>
2425
@@ -43,24 +44,8 @@ class remove_function_pointerst
4344 goto_programt &goto_program,
4445 const irep_idt &function_id);
4546
46- // a set of function symbols
47- using functionst = remove_const_function_pointerst::functionst;
48-
49- // / Replace a call to a dynamic function at location
50- // / target in the given goto-program by a case-split
51- // / over a given set of functions
52- // / \param goto_program: The goto program that contains target
53- // / \param function_id: Name of function containing the target
54- // / \param target: location with function call with function pointer
55- // / \param functions: The set of functions to consider
56- void remove_function_pointer (
57- goto_programt &goto_program,
58- const irep_idt &function_id,
59- goto_programt::targett target,
60- const functionst &functions);
61-
6247protected:
63- messaget log ;
48+ message_handlert &message_handler ;
6449 const namespacet ns;
6550 symbol_tablet &symbol_table;
6651 bool add_safety_assertion;
@@ -88,21 +73,6 @@ class remove_function_pointerst
8873
8974 typedef std::map<irep_idt, code_typet> type_mapt;
9075 type_mapt type_map;
91-
92- bool is_type_compatible (
93- bool return_value_used,
94- const code_typet &call_type,
95- const code_typet &function_type);
96-
97- bool arg_is_type_compatible (
98- const typet &call_type,
99- const typet &function_type);
100-
101- void fix_argument_types (code_function_callt &function_call);
102- void fix_return_type (
103- const irep_idt &in_function_id,
104- code_function_callt &function_call,
105- goto_programt &dest);
10676};
10777
10878remove_function_pointerst::remove_function_pointerst (
@@ -111,7 +81,7 @@ remove_function_pointerst::remove_function_pointerst(
11181 bool _add_safety_assertion,
11282 bool only_resolve_const_fps,
11383 const goto_functionst &goto_functions)
114- : log (_message_handler),
84+ : message_handler (_message_handler),
11585 ns(_symbol_table),
11686 symbol_table(_symbol_table),
11787 add_safety_assertion(_add_safety_assertion),
@@ -130,9 +100,10 @@ remove_function_pointerst::remove_function_pointerst(
130100 }
131101}
132102
133- bool remove_function_pointerst:: arg_is_type_compatible (
103+ static bool arg_is_type_compatible (
134104 const typet &call_type,
135- const typet &function_type)
105+ const typet &function_type,
106+ const namespacet &ns)
136107{
137108 if (call_type == function_type)
138109 return true ;
@@ -156,10 +127,11 @@ bool remove_function_pointerst::arg_is_type_compatible(
156127 pointer_offset_bits (function_type, ns);
157128}
158129
159- bool remove_function_pointerst::is_type_compatible (
130+ bool function_is_type_convertable (
160131 bool return_value_used,
161132 const code_typet &call_type,
162- const code_typet &function_type)
133+ const code_typet &function_type,
134+ const namespacet &ns)
163135{
164136 // we are willing to ignore anything that's returned
165137 // if we call with 'void'
@@ -172,8 +144,8 @@ bool remove_function_pointerst::is_type_compatible(
172144 }
173145 else
174146 {
175- if (!arg_is_type_compatible (call_type. return_type (),
176- function_type.return_type ()))
147+ if (!arg_is_type_compatible (
148+ call_type. return_type (), function_type.return_type (), ns ))
177149 return false ;
178150 }
179151
@@ -198,16 +170,15 @@ bool remove_function_pointerst::is_type_compatible(
198170 return false ;
199171
200172 for (std::size_t i=0 ; i<call_parameters.size (); i++)
201- if (!arg_is_type_compatible (call_parameters[i]. type (),
202- function_parameters[i].type ()))
173+ if (!arg_is_type_compatible (
174+ call_parameters[i]. type (), function_parameters[i].type (), ns ))
203175 return false ;
204176 }
205177
206178 return true ;
207179}
208180
209- void remove_function_pointerst::fix_argument_types (
210- code_function_callt &function_call)
181+ static void fix_argument_types (code_function_callt &function_call)
211182{
212183 const code_typet &code_type = to_code_type (function_call.function ().type ());
213184
@@ -230,9 +201,10 @@ void remove_function_pointerst::fix_argument_types(
230201 }
231202}
232203
233- void remove_function_pointerst:: fix_return_type (
204+ static void fix_return_type (
234205 const irep_idt &in_function_id,
235206 code_function_callt &function_call,
207+ symbol_tablet &symbol_table,
236208 goto_programt &dest)
237209{
238210 // are we returning anything at all?
@@ -245,6 +217,7 @@ void remove_function_pointerst::fix_return_type(
245217 if (function_call.lhs ().type () == code_type.return_type ())
246218 return ;
247219
220+ const namespacet ns (symbol_table);
248221 const symbolt &function_symbol =
249222 ns.lookup (to_symbol_expr (function_call.function ()).get_identifier ());
250223
@@ -292,6 +265,7 @@ void remove_function_pointerst::remove_function_pointer(
292265 remove_const_function_pointerst::functionst functions;
293266 does_remove_constt const_removal_check (goto_program, ns);
294267 const auto does_remove_const = const_removal_check ();
268+ messaget log{message_handler};
295269 if (does_remove_const.first )
296270 {
297271 log.warning ().source_location = does_remove_const.second ;
@@ -344,7 +318,8 @@ void remove_function_pointerst::remove_function_pointer(
344318 continue ;
345319
346320 // type-compatible?
347- if (!is_type_compatible (return_value_used, call_type, t.second ))
321+ if (!function_is_type_convertable (
322+ return_value_used, call_type, t.second , ns))
348323 continue ;
349324
350325 if (t.first ==" pthread_mutex_cleanup" )
@@ -355,14 +330,56 @@ void remove_function_pointerst::remove_function_pointer(
355330 }
356331 }
357332
358- remove_function_pointer (goto_program, function_id, target, functions);
333+ ::remove_function_pointer (
334+ message_handler,
335+ symbol_table,
336+ goto_program,
337+ function_id,
338+ target,
339+ functions,
340+ add_safety_assertion);
359341}
360342
361- void remove_function_pointerst::remove_function_pointer (
343+ static std::string function_pointer_assertion_comment (
344+ const std::unordered_set<symbol_exprt, irep_hash> &candidates)
345+ {
346+ std::stringstream comment;
347+
348+ comment << " dereferenced function pointer at must be " ;
349+
350+ if (candidates.size () == 1 )
351+ {
352+ comment << candidates.begin ()->get_identifier ();
353+ }
354+ else if (candidates.empty ())
355+ {
356+ comment.str (" no candidates for dereferenced function pointer" );
357+ }
358+ else
359+ {
360+ comment << " one of [" ;
361+
362+ join_strings (
363+ comment,
364+ candidates.begin (),
365+ candidates.end (),
366+ " , " ,
367+ [](const symbol_exprt &s) { return s.get_identifier (); });
368+
369+ comment << ' ]' ;
370+ }
371+
372+ return comment.str ();
373+ }
374+
375+ void remove_function_pointer (
376+ message_handlert &message_handler,
377+ symbol_tablet &symbol_table,
362378 goto_programt &goto_program,
363379 const irep_idt &function_id,
364380 goto_programt::targett target,
365- const functionst &functions)
381+ const std::unordered_set<symbol_exprt, irep_hash> &functions,
382+ const bool add_safety_assertion)
366383{
367384 const exprt &function = target->call_function ();
368385 const exprt &pointer = to_dereference_expr (function).pointer ();
@@ -387,7 +404,7 @@ void remove_function_pointerst::remove_function_pointer(
387404 fix_argument_types (new_call);
388405
389406 goto_programt tmp;
390- fix_return_type (function_id, new_call, tmp);
407+ fix_return_type (function_id, new_call, symbol_table, tmp);
391408
392409 auto call = new_code_calls.add (goto_programt::make_function_call (new_call));
393410 new_code_calls.destructive_append (tmp);
@@ -411,7 +428,8 @@ void remove_function_pointerst::remove_function_pointer(
411428 goto_programt::targett t =
412429 new_code_gotos.add (goto_programt::make_assertion (false_exprt ()));
413430 t->source_location .set_property_class (" pointer dereference" );
414- t->source_location .set_comment (" invalid function pointer" );
431+ t->source_location .set_comment (
432+ function_pointer_assertion_comment (functions));
415433 }
416434 new_code_gotos.add (goto_programt::make_assumption (false_exprt ()));
417435
@@ -449,6 +467,7 @@ void remove_function_pointerst::remove_function_pointer(
449467 target->type =OTHER;
450468
451469 // report statistics
470+ messaget log{message_handler};
452471 log.statistics ().source_location = target->source_location ;
453472 log.statistics () << " replacing function pointer by " << functions.size ()
454473 << " possible targets" << messaget::eom;
0 commit comments