Skip to content

Commit 8eef445

Browse files
committed
De-duplicate and fix code of value-set backed function pointer removal
The existing code suffered from the same problems that were previously fixed in e4d7411 for type-based function pointer removal. Really, there should just be one such implementation across the code base.
1 parent 7bfbfce commit 8eef445

File tree

3 files changed

+75
-167
lines changed

3 files changed

+75
-167
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#include <assert.h>
2+
3+
struct PtrWrapperInner
4+
{
5+
int *value;
6+
};
7+
8+
struct PtrWrapper
9+
{
10+
int *value;
11+
struct PtrWrapperInner inner;
12+
};
13+
14+
struct AltPtrWrapperInner
15+
{
16+
int *value;
17+
};
18+
19+
struct AltPtrWrapper
20+
{
21+
unsigned int *value;
22+
// A) Doesn't work
23+
struct AltPtrWrapperInner inner;
24+
// B) Works
25+
// struct PtrWrapperInner inner;
26+
};
27+
28+
void fn(struct PtrWrapper wrapper)
29+
{
30+
assert(*wrapper.value == 10);
31+
assert(*wrapper.inner.value == 10);
32+
}
33+
34+
int main()
35+
{
36+
int ret = 10;
37+
int *ptr = &ret;
38+
39+
struct AltPtrWrapper alt;
40+
alt.inner.value = ptr;
41+
alt.value = ptr;
42+
43+
// Casting the structure itself works.
44+
struct PtrWrapper wrapper = *(struct PtrWrapper *)&alt;
45+
assert(*wrapper.value == 10);
46+
assert(*wrapper.inner.value == 10);
47+
48+
// This only works if there is one level of casting.
49+
int (*alias)(struct AltPtrWrapper) = (int (*)(struct AltPtrWrapper))fn;
50+
alias(alt);
51+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
CORE
2+
main.c
3+
--value-set-fi-fp-removal
4+
^VERIFICATION SUCCESSFUL$
5+
^EXIT=0$
6+
^SIGNAL=0$
7+
--
8+
--
9+
This test checks that the value-set-fi-based function pointer removal performs
10+
suitable type conversion when argument and parameter types do not match. Source
11+
file is a copy of cbmc/Function_Pointer19/main.c.

src/goto-instrument/value_set_fi_fp_removal.cpp

Lines changed: 13 additions & 167 deletions
Original file line numberDiff line numberDiff line change
@@ -8,176 +8,14 @@ Author: Daniel Kroening, [email protected]
88

99
#include "value_set_fi_fp_removal.h"
1010

11-
#include <goto-programs/goto_model.h>
12-
13-
#include <pointer-analysis/value_set_analysis_fi.h>
14-
15-
#include <util/c_types.h>
16-
#include <util/fresh_symbol.h>
1711
#include <util/message.h>
1812
#include <util/namespace.h>
1913
#include <util/pointer_expr.h>
20-
#include <util/std_code.h>
21-
22-
#ifdef USE_STD_STRING
23-
# include <util/dstring.h>
24-
#endif
25-
26-
void fix_argument_types(
27-
code_function_callt &function_call,
28-
const namespacet &ns)
29-
{
30-
const code_typet &code_type =
31-
to_code_type(ns.follow(function_call.function().type()));
32-
33-
const code_typet::parameterst &function_parameters = code_type.parameters();
34-
35-
code_function_callt::argumentst &call_arguments = function_call.arguments();
36-
37-
for(std::size_t i = 0; i < function_parameters.size(); i++)
38-
{
39-
// casting pointers might result in more arguments than function parameters
40-
if(i < call_arguments.size())
41-
{
42-
call_arguments[i] = typecast_exprt::conditional_cast(
43-
call_arguments[i], function_parameters[i].type());
44-
}
45-
}
46-
}
47-
48-
void fix_return_type(
49-
code_function_callt &function_call,
50-
goto_programt &dest,
51-
goto_modelt &goto_model)
52-
{
53-
// are we returning anything at all?
54-
if(function_call.lhs().is_nil())
55-
return;
56-
57-
const namespacet ns(goto_model.symbol_table);
58-
59-
const code_typet &code_type =
60-
to_code_type(ns.follow(function_call.function().type()));
61-
62-
// type already ok?
63-
if(function_call.lhs().type() == code_type.return_type())
64-
return;
65-
66-
const symbolt &function_symbol =
67-
ns.lookup(to_symbol_expr(function_call.function()).get_identifier());
68-
69-
symbolt &tmp_symbol = get_fresh_aux_symbol(
70-
code_type.return_type(),
71-
id2string(function_call.source_location().get_function()),
72-
"tmp_return_val_" + id2string(function_symbol.base_name),
73-
function_call.source_location(),
74-
function_symbol.mode,
75-
goto_model.symbol_table);
76-
77-
const symbol_exprt tmp_symbol_expr = tmp_symbol.symbol_expr();
78-
79-
exprt old_lhs = function_call.lhs();
80-
function_call.lhs() = tmp_symbol_expr;
81-
82-
dest.add(goto_programt::make_assignment(
83-
code_assignt(old_lhs, typecast_exprt(tmp_symbol_expr, old_lhs.type()))));
84-
}
85-
86-
void remove_function_pointer(
87-
goto_programt &goto_program,
88-
goto_programt::targett target,
89-
const std::set<symbol_exprt> &functions,
90-
goto_modelt &goto_model)
91-
{
92-
const exprt &function = as_const(*target).call_function();
93-
PRECONDITION(function.id() == ID_dereference);
94-
95-
// this better have the right type
96-
code_typet call_type = to_code_type(function.type());
97-
98-
// refine the type in case the forward declaration was incomplete
99-
if(call_type.has_ellipsis() && call_type.parameters().empty())
100-
{
101-
call_type.remove_ellipsis();
102-
for(const auto &argument : as_const(*target).call_arguments())
103-
call_type.parameters().push_back(code_typet::parametert(argument.type()));
104-
}
105-
106-
const exprt &pointer = to_dereference_expr(function).pointer();
107-
108-
// the final target is a skip
109-
goto_programt final_skip;
110-
goto_programt::targett t_final = final_skip.add(goto_programt::make_skip());
111-
112-
// build the calls and gotos
113-
114-
goto_programt new_code_calls;
115-
goto_programt new_code_gotos;
116-
117-
for(const auto &fun : functions)
118-
{
119-
// call function
120-
goto_programt::targett t1 =
121-
new_code_calls.add(goto_programt::make_function_call(
122-
as_const(*target).call_lhs(),
123-
fun,
124-
as_const(*target).call_arguments(),
125-
target->source_location()));
126-
127-
// the signature of the function might not match precisely
128-
const namespacet ns(goto_model.symbol_table);
129-
fix_argument_types(to_code_function_call(t1->code_nonconst()), ns);
130-
fix_return_type(
131-
to_code_function_call(t1->code_nonconst()), new_code_calls, goto_model);
132-
133-
// goto final
134-
new_code_calls.add(goto_programt::make_goto(t_final, true_exprt()));
135-
136-
// goto to call
137-
address_of_exprt address_of(fun, pointer_type(fun.type()));
138-
139-
new_code_gotos.add(goto_programt::make_goto(
140-
t1,
141-
equal_exprt(
142-
pointer,
143-
typecast_exprt::conditional_cast(address_of, pointer.type()))));
144-
}
145-
146-
goto_programt::targett t =
147-
new_code_gotos.add(goto_programt::make_assertion(false_exprt()));
148-
t->source_location_nonconst().set_property_class("pointer dereference");
149-
t->source_location_nonconst().set_comment("invalid function pointer");
150-
151-
goto_programt new_code;
152-
153-
// patch them all together
154-
new_code.destructive_append(new_code_gotos);
155-
new_code.destructive_append(new_code_calls);
156-
new_code.destructive_append(final_skip);
157-
158-
// set locations
159-
for(auto &instruction : new_code.instructions)
160-
{
161-
irep_idt property_class =
162-
instruction.source_location().get_property_class();
163-
irep_idt comment = instruction.source_location().get_comment();
164-
instruction.source_location_nonconst() = target->source_location();
165-
if(!property_class.empty())
166-
instruction.source_location_nonconst().set_property_class(property_class);
167-
if(!comment.empty())
168-
instruction.source_location_nonconst().set_comment(comment);
169-
}
17014

171-
goto_programt::targett next_target = target;
172-
next_target++;
173-
174-
goto_program.destructive_insert(next_target, new_code);
15+
#include <goto-programs/goto_model.h>
16+
#include <goto-programs/remove_function_pointers.h>
17517

176-
// We preserve the original dereferencing to possibly catch
177-
// further pointer-related errors.
178-
*target = goto_programt::make_other(
179-
code_expressiont(function), function.source_location());
180-
}
18+
#include <pointer-analysis/value_set_analysis_fi.h>
18119

18220
void value_set_fi_fp_removal(
18321
goto_modelt &goto_model,
@@ -210,7 +48,7 @@ void value_set_fi_fp_removal(
21048
const auto &pointer = to_dereference_expr(function).pointer();
21149
auto addresses = value_sets.get_values(f.first, target, pointer);
21250

213-
std::set<symbol_exprt> functions;
51+
std::unordered_set<symbol_exprt, irep_hash> functions;
21452

21553
for(const auto &address : addresses)
21654
{
@@ -230,8 +68,16 @@ void value_set_fi_fp_removal(
23068
<< " function: " << f.get_identifier() << messaget::eom;
23169

23270
if(functions.size() > 0)
71+
{
23372
remove_function_pointer(
234-
f.second.body, target, functions, goto_model);
73+
message_handler,
74+
goto_model.symbol_table,
75+
f.second.body,
76+
f.first,
77+
target,
78+
functions,
79+
true);
80+
}
23581
}
23682
}
23783
}

0 commit comments

Comments
 (0)