30
30
#include " compute_called_functions.h"
31
31
#include " remove_const_function_pointers.h"
32
32
33
+ #include < iostream>
34
+
35
+ #define UNKNOWN_ASSIGN " ##unknown##"
36
+
33
37
class remove_function_pointerst :public messaget
34
38
{
35
39
public:
@@ -48,6 +52,12 @@ class remove_function_pointerst:public messaget
48
52
const namespacet ns;
49
53
symbol_tablet &symbol_table;
50
54
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
+
51
61
52
62
// We can optionally halt the FP removal if we aren't able to use
53
63
// remove_const_function_pointerst to successfully narrow to a small
@@ -80,6 +90,13 @@ class remove_function_pointerst:public messaget
80
90
code_function_callt &function_call,
81
91
goto_programt &dest);
82
92
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
+
83
100
void
84
101
compute_address_taken_in_symbols (std::unordered_set<irep_idt> &address_taken)
85
102
{
@@ -90,6 +107,12 @@ class remove_function_pointerst:public messaget
90
107
}
91
108
};
92
109
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
+
93
116
remove_function_pointerst::remove_function_pointerst (
94
117
message_handlert &_message_handler,
95
118
symbol_tablet &_symbol_table,
@@ -99,6 +122,9 @@ remove_function_pointerst::remove_function_pointerst(
99
122
ns(_symbol_table),
100
123
symbol_table(_symbol_table),
101
124
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 ),
102
128
only_resolve_const_fps(only_resolve_const_fps)
103
129
{
104
130
compute_address_taken_in_symbols (address_taken);
@@ -255,6 +281,7 @@ void remove_function_pointerst::fix_return_type(
255
281
old_lhs, typecast_exprt (tmp_symbol_expr, old_lhs.type ()));
256
282
}
257
283
284
+
258
285
void remove_function_pointerst::remove_function_pointer (
259
286
goto_programt &goto_program,
260
287
goto_programt::targett target)
@@ -348,6 +375,41 @@ void remove_function_pointerst::remove_function_pointer(
348
375
}
349
376
}
350
377
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
+
351
413
// the final target is a skip
352
414
goto_programt final_skip;
353
415
@@ -430,6 +492,10 @@ void remove_function_pointerst::remove_function_pointer(
430
492
statistics ().source_location =target->source_location ;
431
493
statistics () << " replacing function pointer by "
432
494
<< 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 ();
433
499
434
500
// list the names of functions when verbosity is at debug level
435
501
conditional_output (
@@ -451,6 +517,7 @@ void remove_function_pointerst::remove_function_pointer(
451
517
});
452
518
}
453
519
520
+
454
521
bool remove_function_pointerst::remove_function_pointers (
455
522
goto_programt &goto_program)
456
523
{
@@ -459,13 +526,12 @@ bool remove_function_pointerst::remove_function_pointers(
459
526
Forall_goto_program_instructions (target, goto_program)
460
527
if (target->is_function_call ())
461
528
{
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 );
464
530
465
- if (code.function ().id ()== ID_dereference)
531
+ if (code.function ().id () == ID_dereference)
466
532
{
467
533
remove_function_pointer (goto_program, target);
468
- did_something= true ;
534
+ did_something = true ;
469
535
}
470
536
}
471
537
@@ -475,8 +541,10 @@ bool remove_function_pointerst::remove_function_pointers(
475
541
return did_something;
476
542
}
477
543
544
+
478
545
void remove_function_pointerst::operator ()(goto_functionst &functions)
479
546
{
547
+ get_all_writes_to_pointers (functions);
480
548
bool did_something=false ;
481
549
482
550
for (goto_functionst::function_mapt::iterator f_it=
@@ -490,8 +558,23 @@ void remove_function_pointerst::operator()(goto_functionst &functions)
490
558
did_something=true ;
491
559
}
492
560
561
+
493
562
if (did_something)
563
+ {
494
564
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
+ }
495
578
}
496
579
497
580
bool remove_function_pointers (message_handlert &_message_handler,
@@ -535,10 +618,57 @@ void remove_function_pointers(message_handlert &_message_handler,
535
618
bool add_safety_assertion,
536
619
bool only_remove_const_fps)
537
620
{
621
+
538
622
remove_function_pointers (
539
623
_message_handler,
540
624
goto_model.symbol_table ,
541
625
goto_model.goto_functions ,
542
626
add_safety_assertion,
543
627
only_remove_const_fps);
544
628
}
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