Skip to content

Commit da91cea

Browse files
Daniel Kroeningpolgreen
Daniel Kroening
authored andcommitted
goto-instrument: function pointer removal with value_set_fi
This adds a new option to goto-instrument for removing function pointers. The points-to analysis is done using flow-insensitive value sets, which is more precise than using the signature of the function to identify the points-to set. Co-authored-by: Elizabeth Polgreen [email protected]
1 parent e06f678 commit da91cea

File tree

18 files changed

+500
-0
lines changed

18 files changed

+500
-0
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#include <assert.h>
2+
3+
typedef void (*fp_t)();
4+
5+
void f()
6+
{
7+
}
8+
9+
void g()
10+
{
11+
}
12+
13+
int main(void)
14+
{
15+
fp_t fp = f;
16+
fp();
17+
18+
// this would fool an analysis that looks for functions whose address is taken
19+
fp_t other_fp = g;
20+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
CORE
2+
test.c
3+
--value-set-fi-fp-removal
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^ function: f$
7+
--
8+
^ function: g$
9+
--
10+
This test checks that the value-set-fi-based function pointer removal
11+
precisely identifies the function to call for a particular function pointer
12+
call.
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
2+
typedef void (*fp_t)(int, int);
3+
4+
void add(int a, int b)
5+
{
6+
}
7+
void subtract(int a, int b)
8+
{
9+
}
10+
void multiply(int a, int b)
11+
{
12+
}
13+
14+
int main()
15+
{
16+
// fun_ptr_arr is an array of function pointers
17+
void (*fun_ptr_arr[])(int, int) = {add, subtract, add};
18+
19+
// Multiply should not be added into the value set
20+
fp_t other_fp = multiply;
21+
void (*fun_ptr_arr2[])(int, int) = {multiply, subtract, add};
22+
23+
// the fp removal over-approximates and assumes this could be any pointer in the array
24+
(*fun_ptr_arr[0])(1, 1);
25+
26+
return 0;
27+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
CORE
2+
test.c
3+
--value-set-fi-fp-removal
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^ function: add$
7+
^ function: subtract$
8+
--
9+
^ function: multiply$
10+
--
11+
This test checks that the value-set-fi-based function pointer removal
12+
precisely identifies the function to call for a particular function pointer
13+
call.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
typedef void (*fp_t)(int, int);
2+
3+
void add(int a, int b)
4+
{
5+
}
6+
void subtract(int a, int b)
7+
{
8+
}
9+
void multiply(int a, int b)
10+
{
11+
}
12+
13+
int main()
14+
{
15+
// fun_ptr_arr is an array of function pointers
16+
struct my_struct
17+
{
18+
fp_t first_pointer;
19+
fp_t second_pointer;
20+
} struct1;
21+
22+
struct1.first_pointer = add;
23+
24+
// Multiply and subtract should not be added into the value set
25+
fp_t other_fp = multiply;
26+
struct1.second_pointer = subtract;
27+
28+
// this pointer can only be "add"
29+
struct1.first_pointer(1, 1);
30+
31+
return 0;
32+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
CORE
2+
test.c
3+
--value-set-fi-fp-removal
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^ function: add$
7+
--
8+
^ function: multiply$
9+
^ function: subtract$
10+
--
11+
This test checks that the value-set-fi-based function pointer removal
12+
precisely identifies the function to call for a particular function pointer
13+
call.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#include <assert.h>
2+
3+
typedef void (*fp_t)();
4+
5+
void f()
6+
{
7+
}
8+
9+
void g()
10+
{
11+
}
12+
13+
int main(void)
14+
{
15+
fp_t fp;
16+
fp();
17+
18+
// the value set is empty, defaults to standard function pointer removal behaviour
19+
fp_t other_fp = g;
20+
other_fp = f;
21+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
test.c
3+
--value-set-fi-fp-removal
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^file test.c line 16 function main: replacing function pointer by 2 possible targets$
7+
--
8+
This test checks that the value-set-fi-based function pointer removal
9+
precisely identifies the function to call for a particular function pointer
10+
call.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#include <assert.h>
2+
3+
typedef void (*fp_t)();
4+
5+
void f(int x)
6+
{
7+
}
8+
9+
void g(int y)
10+
{
11+
}
12+
13+
int main(void)
14+
{
15+
fp_t fp;
16+
fp();
17+
18+
// the value set is empty, defaults to standard function pointer removal behaviour
19+
fp_t other_fp = g;
20+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
test.c
3+
--value-set-fi-fp-removal
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^file test.c line 16 function main: replacing function pointer by 0 possible targets$
7+
--
8+
This test checks that the value-set-fi-based function pointer removal
9+
precisely identifies the function to call for a particular function pointer
10+
call.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#include <assert.h>
2+
3+
typedef void (*fp_t)(void);
4+
5+
void f()
6+
{
7+
}
8+
9+
void g()
10+
{
11+
}
12+
13+
int main(void)
14+
{
15+
fp_t fp = f;
16+
fp_t decoy_fp = g;
17+
fp_t *ptr_to_func_ptr = &fp; // a pointer to a function pointer
18+
(*ptr_to_func_ptr)();
19+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
CORE
2+
test.c
3+
--value-set-fi-fp-removal
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^ function: f$
7+
--
8+
^ function: g$
9+
--
10+
This test checks that the value-set-fi-based function pointer removal
11+
precisely identifies the function to call for a particular function pointer
12+
call.

src/goto-instrument/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ SRC = accelerate/accelerate.cpp \
6767
uninitialized.cpp \
6868
unwind.cpp \
6969
unwindset.cpp \
70+
value_set_fi_fp_removal.cpp \
7071
wmm/abstract_event.cpp \
7172
wmm/cycle_collection.cpp \
7273
wmm/data_dp.cpp \

src/goto-instrument/goto_instrument_parse_options.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ Author: Daniel Kroening, [email protected]
5454
#include <pointer-analysis/goto_program_dereference.h>
5555
#include <pointer-analysis/show_value_sets.h>
5656
#include <pointer-analysis/value_set_analysis.h>
57+
#include <pointer-analysis/value_set_analysis_fi.h>
5758

5859
#include <analyses/call_graph.h>
5960
#include <analyses/constant_propagator.h>
@@ -111,6 +112,7 @@ Author: Daniel Kroening, [email protected]
111112
#include "undefined_functions.h"
112113
#include "uninitialized.h"
113114
#include "unwind.h"
115+
#include "value_set_fi_fp_removal.h"
114116
#include "wmm/weak_memory.h"
115117

116118
/// invoke main modules
@@ -1198,6 +1200,12 @@ void goto_instrument_parse_optionst::instrument_goto_program()
11981200
exit(CPROVER_EXIT_USAGE_ERROR);
11991201
}
12001202

1203+
if(cmdline.isset("value-set-fi-fp-removal"))
1204+
{
1205+
value_set_fi_fp_removal(goto_model, ui_message_handler);
1206+
do_indirect_call_and_rtti_removal();
1207+
}
1208+
12011209
// replace function pointers, if explicitly requested
12021210
if(cmdline.isset("remove-function-pointers"))
12031211
{
@@ -1867,6 +1875,9 @@ void goto_instrument_parse_optionst::help()
18671875
" --no-caching disable caching of intermediate results during transitive function inlining\n" // NOLINT(*)
18681876
" --log <file> log in json format which code segments were inlined, use with --function-inline\n" // NOLINT(*)
18691877
" --remove-function-pointers replace function pointers by case statement over function calls\n" // NOLINT(*)
1878+
" --value-set-fi-fp-removal build flow-insensitive value set and replace function pointers by a case statement\n" // NOLINT(*)
1879+
" over the possible assignments. If the set of possible assignments is empty the function pointer\n" // NOLINT(*)
1880+
" is removed using the standard remove-function-pointers pass. \n" // NOLINT(*)
18701881
HELP_RESTRICT_FUNCTION_POINTER
18711882
HELP_REMOVE_CALLS_NO_BODY
18721883
HELP_REMOVE_CONST_FUNCTION_POINTERS

src/goto-instrument/goto_instrument_parse_options.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ Author: Daniel Kroening, [email protected]
8383
"(full-slice)(reachability-slice)(slice-global-inits)" \
8484
"(fp-reachability-slice):" \
8585
"(inline)(partial-inline)(function-inline):(log):(no-caching)" \
86+
"(value-set-fi-fp-removal)" \
8687
OPT_REMOVE_CONST_FUNCTION_POINTERS \
8788
"(print-internal-representation)" \
8889
"(remove-function-pointers)" \

0 commit comments

Comments
 (0)