Skip to content

Commit f16af50

Browse files
committed
Add a unit test for remove function pointers
matching variant function pointer to a complete function.
1 parent bb73e61 commit f16af50

File tree

2 files changed

+158
-0
lines changed

2 files changed

+158
-0
lines changed

unit/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ SRC += analyses/ai/ai.cpp \
1515
analyses/does_remove_const/does_type_preserve_const_correctness.cpp \
1616
analyses/does_remove_const/is_type_at_least_as_const_as.cpp \
1717
analyses/remove_function_pointers.cpp \
18+
analyses/remove_function_pointers_refine.cpp \
1819
analyses/remove_returns.cpp \
1920
big-int/big-int.cpp \
2021
compound_block_locations.cpp \
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
/*******************************************************************\
2+
Module: Unit tests for module remove_function_pointers.refine_call_type
3+
4+
Author: Diffblue Ltd.
5+
6+
Date: May 2019
7+
8+
\*******************************************************************/
9+
10+
/// \file
11+
/// Unit tests for module remove_function_pointers
12+
13+
#include <testing-utils/message.h>
14+
#include <testing-utils/use_catch.h>
15+
16+
#include <util/arith_tools.h>
17+
#include <util/c_types.h>
18+
#include <util/std_code.h>
19+
20+
#include <goto-programs/goto_convert_functions.h>
21+
#include <goto-programs/goto_model.h>
22+
#include <goto-programs/remove_function_pointers.h>
23+
24+
SCENARIO(
25+
"List potential targets works for ellipsis",
26+
"[core][goto-programs][list_potential_targets]")
27+
{
28+
goto_modelt goto_model;
29+
// create one instance of the function type, they are all
30+
// going to have the same signature
31+
32+
symbolt int_param;
33+
int_param.name = "int_param";
34+
int_param.mode = ID_C;
35+
int_param.type = signedbv_typet{32};
36+
goto_model.symbol_table.add(int_param);
37+
38+
code_typet::parameterst parameters;
39+
parameters.emplace_back(signedbv_typet{32});
40+
parameters.back().set_identifier("int_param");
41+
auto func_empty_type = code_typet{{}, empty_typet{}};
42+
auto func_ellipsis_type = code_typet{{}, empty_typet{}};
43+
func_ellipsis_type.make_ellipsis();
44+
auto func_one_arg_type = code_typet{parameters, empty_typet{}};
45+
// create an empty code block, to act as the functions' body
46+
code_blockt func_body = code_blockt{};
47+
48+
irep_idt f_name{"f"};
49+
50+
// void f(...){};
51+
symbolt f;
52+
f.name = f_name;
53+
f.mode = ID_C;
54+
f.type = func_ellipsis_type; // takes anything
55+
f.value = func_body;
56+
goto_model.symbol_table.add(f);
57+
58+
// void g(int){};
59+
symbolt g;
60+
g.name = "g";
61+
g.mode = ID_C;
62+
g.type = func_one_arg_type; // takes one int
63+
g.value = func_body;
64+
goto_model.symbol_table.add(g);
65+
66+
// create array with function pointer elements
67+
array_typet fp_array_type(
68+
pointer_typet{func_ellipsis_type, 64}, from_integer(2, index_type()));
69+
array_exprt fp_array{{}, fp_array_type};
70+
71+
fp_array.copy_to_operands(address_of_exprt{f.symbol_expr()});
72+
fp_array.copy_to_operands(address_of_exprt{g.symbol_expr()});
73+
74+
// fpa = fparray {f1, f2};
75+
symbolt fpa;
76+
fpa.name = "fpa";
77+
fpa.mode = ID_C;
78+
fpa.type = fp_array_type;
79+
fpa.value = fp_array;
80+
81+
goto_model.symbol_table.add(fpa);
82+
83+
irep_idt fn_ptr_name{"fn_ptr"};
84+
85+
// pointer to fn call
86+
symbolt fn_ptr;
87+
fn_ptr.name = fn_ptr_name;
88+
fn_ptr.mode = ID_C;
89+
fn_ptr.type = pointer_typet{func_ellipsis_type, 64};
90+
goto_model.symbol_table.add(fn_ptr);
91+
92+
// symbol for indexing the array
93+
symbolt z;
94+
z.name = "z";
95+
z.mode = ID_C;
96+
z.type = index_type();
97+
goto_model.symbol_table.add(z);
98+
99+
// create function with pointer function call instruction
100+
101+
// void entry(){z; array; fn_ptr = array[z]; *fn_ptr(z)};
102+
symbolt entry;
103+
entry.name = "entry";
104+
entry.mode = ID_C;
105+
entry.type = func_empty_type;
106+
107+
code_function_callt::argumentst arguments;
108+
arguments.emplace_back(z.symbol_expr());
109+
110+
code_blockt entry_body{
111+
{// fn_ptr = array[z];
112+
code_assignt{fn_ptr.symbol_expr(),
113+
index_exprt{fp_array,
114+
z.symbol_expr(),
115+
pointer_type(func_ellipsis_type)}},
116+
// *fn_ptr();
117+
code_function_callt{dereference_exprt{fn_ptr.symbol_expr()}, arguments}}};
118+
entry.value = entry_body;
119+
goto_model.symbol_table.add(entry);
120+
121+
WHEN("list_potential_targets is run")
122+
{
123+
goto_convert(goto_model, null_message_handler);
124+
125+
// goto convert removes ellipsis so we need to re-insert them
126+
auto &f_symbol = goto_model.symbol_table.get_writeable_ref(f_name);
127+
to_code_type(f_symbol.type).make_ellipsis();
128+
auto &fn_ptr_symbol =
129+
goto_model.symbol_table.get_writeable_ref(fn_ptr_name);
130+
to_code_type(fn_ptr_symbol.type.subtype()).make_ellipsis();
131+
132+
auto &goto_functions = goto_model.goto_functions;
133+
for(auto &goto_function_pair : goto_functions.function_map)
134+
{
135+
auto &goto_function = goto_function_pair.second;
136+
auto &goto_program = goto_function.body;
137+
for(auto &instruction : goto_program.instructions)
138+
{
139+
if(instruction.is_function_call())
140+
{
141+
code_function_callt function_call = instruction.get_function_call();
142+
auto &function = to_dereference_expr(function_call.function());
143+
to_code_type(function.type()).make_ellipsis();
144+
instruction.set_function_call(function_call);
145+
}
146+
}
147+
}
148+
149+
auto target_map =
150+
get_function_pointer_targets(null_message_handler, goto_model);
151+
THEN("there should be 4 targets recognised")
152+
{
153+
REQUIRE(target_map.size() == 1);
154+
REQUIRE(target_map.begin()->second.size() == 2);
155+
}
156+
}
157+
}

0 commit comments

Comments
 (0)