Skip to content

Commit 237b400

Browse files
Add restrict-function-pointer-by-name option
This works similar to restrict-function-pointer, but for names of individual function pointer variables (globals, locals, parameters) rather than call sites. This isn't applicable to all situations (for example, calling function pointers in structs or function pointers returned from functions), but is more readily applicable to some common use scenarios (e.g. global function pointers loaded at start time like in OpenGL).
1 parent 9799317 commit 237b400

File tree

5 files changed

+154
-16
lines changed

5 files changed

+154
-16
lines changed
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#include <assert.h>
2+
3+
int f(void)
4+
{
5+
return 1;
6+
}
7+
int g(void)
8+
{
9+
return 2;
10+
}
11+
int h(void)
12+
{
13+
return 3;
14+
}
15+
16+
typedef int (*fptr_t)(void);
17+
18+
void use_f(fptr_t fptr)
19+
{
20+
assert(fptr() == 2);
21+
}
22+
23+
int nondet_int(void);
24+
25+
fptr_t g_fptr;
26+
int main(void)
27+
{
28+
int cond = nondet_int();
29+
if(cond)
30+
{
31+
g_fptr = f;
32+
}
33+
else
34+
{
35+
g_fptr = h;
36+
}
37+
int res = g_fptr();
38+
assert(res == 1 || res == 3);
39+
use_f(g);
40+
fptr_t fptr = f;
41+
assert(fptr() == 1);
42+
return 0;
43+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
CORE
2+
test.c
3+
--restrict-function-pointer-by-name main::1::fptr/f --restrict-function-pointer-by-name use_f::fptr/g --restrict-function-pointer-by-name g_fptr/f,h
4+
\[use_f.assertion.2\] line \d+ assertion fptr\(\) == 2: SUCCESS
5+
\[use_f.assertion.1\] line \d+ dereferenced function pointer at use_f.function_pointer_call.1 must be g: SUCCESS
6+
\[main.assertion.1\] line \d+ dereferenced function pointer at main.function_pointer_call.1 must be one of \[(h|f), (h|f)\]: SUCCESS
7+
\[main.assertion.2\] line \d+ assertion res == 1 \|\| res == 3: SUCCESS
8+
\[main.assertion.3\] line \d+ dereferenced function pointer at main.function_pointer_call.2 must be f: SUCCESS
9+
\[main.assertion.4\] line \d+ assertion fptr\(\) == 1: SUCCESS
10+
^EXIT=0$
11+
^SIGNAL=0$

src/goto-instrument/goto_instrument_parse_options.cpp

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1037,13 +1037,20 @@ void goto_instrument_parse_optionst::instrument_goto_program()
10371037
{
10381038
parse_function_pointer_restriction_options_from_cmdline(cmdline, options);
10391039

1040-
const auto function_pointer_restrictions =
1041-
function_pointer_restrictionst::from_options(
1042-
options, log.get_message_handler());
1043-
1044-
if(!function_pointer_restrictions.restrictions.empty())
1040+
if(
1041+
!options.get_list_option(RESTRICT_FUNCTION_POINTER_OPT).empty() ||
1042+
!options.get_list_option(RESTRICT_FUNCTION_POINTER_BY_NAME_OPT).empty() ||
1043+
!options.get_list_option(RESTRICT_FUNCTION_POINTER_FROM_FILE_OPT).empty())
10451044
{
10461045
label_function_pointer_call_sites(goto_model);
1046+
1047+
auto const by_name_restrictions =
1048+
get_function_pointer_by_name_restrictions(goto_model, options);
1049+
1050+
const auto function_pointer_restrictions =
1051+
by_name_restrictions.merge(function_pointer_restrictionst::from_options(
1052+
options, log.get_message_handler()));
1053+
10471054
restrict_function_pointers(goto_model, function_pointer_restrictions);
10481055
}
10491056
}

src/goto-programs/restrict_function_pointers.cpp

Lines changed: 72 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -104,12 +104,13 @@ source_locationt make_function_pointer_restriction_assertion_source_location(
104104
return source_location;
105105
}
106106

107-
template <typename Handler>
108-
void for_each_function_call(goto_functiont &goto_function, Handler handler)
107+
template <typename Handler, typename GotoFunctionT>
108+
void for_each_function_call(GotoFunctionT &&goto_function, Handler handler)
109109
{
110+
using targett = decltype(goto_function.body.instructions.begin());
110111
for_each_instruction_if(
111112
goto_function,
112-
[](goto_programt::targett target) { return target->is_function_call(); },
113+
[](targett target) { return target->is_function_call(); },
113114
handler);
114115
}
115116

@@ -220,6 +221,9 @@ void parse_function_pointer_restriction_options_from_cmdline(
220221
options.set_option(
221222
RESTRICT_FUNCTION_POINTER_FROM_FILE_OPT,
222223
cmdline.get_values(RESTRICT_FUNCTION_POINTER_FROM_FILE_OPT));
224+
options.set_option(
225+
RESTRICT_FUNCTION_POINTER_BY_NAME_OPT,
226+
cmdline.get_values(RESTRICT_FUNCTION_POINTER_BY_NAME_OPT));
223227
}
224228

225229
function_pointer_restrictionst::restrictionst
@@ -244,9 +248,11 @@ function_pointer_restrictionst::merge_function_pointer_restrictions(
244248
return result;
245249
}
246250

247-
function_pointer_restrictionst::restrictionst function_pointer_restrictionst::
248-
parse_function_pointer_restrictions_from_command_line(
249-
const std::list<std::string> &restriction_opts)
251+
function_pointer_restrictionst::restrictionst
252+
function_pointer_restrictionst::
253+
parse_function_pointer_restrictions_from_command_line(
254+
const std::list<std::string> &restriction_opts,
255+
const std::string &option_name)
250256
{
251257
auto function_pointer_restrictions =
252258
function_pointer_restrictionst::restrictionst{};
@@ -361,7 +367,8 @@ function_pointer_restrictionst function_pointer_restrictionst::from_options(
361367
auto const restriction_opts =
362368
options.get_list_option(RESTRICT_FUNCTION_POINTER_OPT);
363369
auto const commandline_restrictions =
364-
parse_function_pointer_restrictions_from_command_line(restriction_opts);
370+
parse_function_pointer_restrictions_from_command_line(
371+
restriction_opts, RESTRICT_FUNCTION_POINTER_OPT);
365372
auto const file_restrictions = parse_function_pointer_restrictions_from_file(
366373
options.get_list_option(RESTRICT_FUNCTION_POINTER_FROM_FILE_OPT),
367374
message_handler);
@@ -459,3 +466,61 @@ void function_pointer_restrictionst::write_to_file(
459466

460467
function_pointer_restrictions_json.output(outFile);
461468
}
469+
function_pointer_restrictionst function_pointer_restrictionst::merge(
470+
const function_pointer_restrictionst &other) const
471+
{
472+
return function_pointer_restrictionst{
473+
merge_function_pointer_restrictions(restrictions, other.restrictions)};
474+
}
475+
476+
function_pointer_restrictionst get_function_pointer_by_name_restrictions(
477+
const goto_modelt &goto_model,
478+
const optionst &options)
479+
{
480+
function_pointer_restrictionst::restrictionst by_name_restrictions =
481+
function_pointer_restrictionst::
482+
parse_function_pointer_restrictions_from_command_line(
483+
options.get_list_option(RESTRICT_FUNCTION_POINTER_BY_NAME_OPT),
484+
RESTRICT_FUNCTION_POINTER_BY_NAME_OPT);
485+
function_pointer_restrictionst::restrictionst restrictions;
486+
for(auto const &goto_function : goto_model.goto_functions.function_map)
487+
{
488+
for_each_function_call(
489+
goto_function.second, [&](goto_programt::const_targett location) {
490+
PRECONDITION(location->is_function_call());
491+
if(can_cast_expr<dereference_exprt>(
492+
location->get_function_call().function()))
493+
{
494+
PRECONDITION(can_cast_expr<symbol_exprt>(
495+
to_dereference_expr(location->get_function_call().function())
496+
.pointer()));
497+
auto const &function_pointer_call_site = to_symbol_expr(
498+
to_dereference_expr(location->get_function_call().function())
499+
.pointer());
500+
auto const &body = goto_function.second.body;
501+
for(auto it = std::prev(location); it != body.instructions.end();
502+
++it)
503+
{
504+
if(
505+
it->is_assign() &&
506+
it->get_assign().lhs() == function_pointer_call_site &&
507+
can_cast_expr<symbol_exprt>(it->get_assign().rhs()))
508+
{
509+
auto const &assign_rhs = to_symbol_expr(it->get_assign().rhs());
510+
auto const restriction =
511+
by_name_restrictions.find(assign_rhs.get_identifier());
512+
if(
513+
restriction != by_name_restrictions.end() &&
514+
restriction->first == assign_rhs.get_identifier())
515+
{
516+
restrictions.emplace(
517+
function_pointer_call_site.get_identifier(),
518+
restriction->second);
519+
}
520+
}
521+
}
522+
}
523+
});
524+
}
525+
return function_pointer_restrictionst{restrictions};
526+
}

src/goto-programs/restrict_function_pointers.h

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,15 @@ Author: Diffblue Ltd.
2929
#define RESTRICT_FUNCTION_POINTER_OPT "restrict-function-pointer"
3030
#define RESTRICT_FUNCTION_POINTER_FROM_FILE_OPT \
3131
"function-pointer-restrictions-file"
32+
#define RESTRICT_FUNCTION_POINTER_BY_NAME_OPT \
33+
"restrict-function-pointer-by-name"
3234

3335
#define OPT_RESTRICT_FUNCTION_POINTER \
3436
"(" RESTRICT_FUNCTION_POINTER_OPT \
3537
"):" \
36-
"(" RESTRICT_FUNCTION_POINTER_FROM_FILE_OPT "):"
38+
"(" RESTRICT_FUNCTION_POINTER_FROM_FILE_OPT \
39+
"):" \
40+
"(" RESTRICT_FUNCTION_POINTER_BY_NAME_OPT "):"
3741

3842
#define HELP_RESTRICT_FUNCTION_POINTER \
3943
"--" RESTRICT_FUNCTION_POINTER_OPT \
@@ -78,14 +82,18 @@ class function_pointer_restrictionst
7882

7983
void write_to_file(const std::string &filename) const;
8084

85+
function_pointer_restrictionst
86+
merge(const function_pointer_restrictionst &other) const;
87+
88+
static restrictionst parse_function_pointer_restrictions_from_command_line(
89+
const std::list<std::string> &restriction_opts,
90+
const std::string &option_name);
91+
8192
protected:
8293
static restrictionst merge_function_pointer_restrictions(
8394
restrictionst lhs,
8495
const restrictionst &rhs);
8596

86-
static restrictionst parse_function_pointer_restrictions_from_command_line(
87-
const std::list<std::string> &restriction_opts);
88-
8997
static restrictionst parse_function_pointer_restrictions_from_file(
9098
const std::list<std::string> &filenames,
9199
message_handlert &message_handler);
@@ -94,6 +102,10 @@ class function_pointer_restrictionst
94102
parse_function_pointer_restriction(const std::string &restriction_opt);
95103
};
96104

105+
function_pointer_restrictionst get_function_pointer_by_name_restrictions(
106+
const goto_modelt &goto_model,
107+
const optionst &options);
108+
97109
/// Apply function pointer restrictions to a goto_model. Each restriction is a
98110
/// mapping from a pointer name to a set of possible targets. Replace calls of
99111
/// these "restricted" pointers with a branch on the value of the function

0 commit comments

Comments
 (0)