Skip to content

Commit a30bc0a

Browse files
committed
Support labels to identify function pointer to restrict
Function pointer indexes may change as code is modified. Labelling function calls provides for a more stable way of referencing. Fixes: #6464
1 parent ee8def3 commit a30bc0a

File tree

6 files changed

+121
-21
lines changed

6 files changed

+121
-21
lines changed

doc/architectural/restrict-function-pointer.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,12 @@ function where function pointers are being called, to this pattern:
7373
```
7474
<function-name>.function_pointer_call.<N>
7575
```
76-
7776
where `N` is referring to which function call it is - so the first call to a
78-
function pointer in a function will have `N=1`, the 5th `N=5` etc.
77+
function pointer in a function will have `N=1`, the 5th `N=5` etc, or
78+
```
79+
<function-name>.<label>
80+
```
81+
when the function call is labelled.
7982

8083
We can call `goto-instrument --restrict-function-pointer
8184
call.function_pointer_call.1/f,g in.gb out.gb`. This can be read as
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#include <assert.h>
2+
3+
typedef int (*fptr_t)(int);
4+
5+
void use_f(fptr_t fptr)
6+
{
7+
labelled_call:
8+
assert(fptr(10) == 11);
9+
}
10+
11+
int f(int x)
12+
{
13+
return x + 1;
14+
}
15+
16+
int g(int x)
17+
{
18+
return x;
19+
}
20+
21+
int main(void)
22+
{
23+
int one = 1;
24+
25+
// We take the address of f and g. In this case remove_function_pointers()
26+
// would create a case distinction involving both f and g in the function
27+
// use_f() above.
28+
use_f(one ? f : g);
29+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
test.c
3+
--restrict-function-pointer use_f.labelled_call/f
4+
\[use_f\.assertion\.1\] line \d+ assertion fptr\(10\) == 11: SUCCESS
5+
^EXIT=0$
6+
^SIGNAL=0$
7+
--
8+
--
9+
This test checks that the function f is called for the first function pointer
10+
call in function use_f when using the label to refer to the call site.

src/goto-programs/restrict_function_pointers.cpp

Lines changed: 57 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -238,15 +238,16 @@ function_pointer_restrictionst::merge_function_pointer_restrictions(
238238
function_pointer_restrictionst::restrictionst
239239
function_pointer_restrictionst::parse_function_pointer_restrictions(
240240
const std::list<std::string> &restriction_opts,
241-
const std::string &option)
241+
const std::string &option,
242+
const goto_modelt &goto_model)
242243
{
243244
auto function_pointer_restrictions =
244245
function_pointer_restrictionst::restrictionst{};
245246

246247
for(const std::string &restriction_opt : restriction_opts)
247248
{
248249
const auto restriction =
249-
parse_function_pointer_restriction(restriction_opt, option);
250+
parse_function_pointer_restriction(restriction_opt, option, goto_model);
250251

251252
const bool inserted = function_pointer_restrictions
252253
.emplace(restriction.first, restriction.second)
@@ -265,10 +266,11 @@ function_pointer_restrictionst::parse_function_pointer_restrictions(
265266

266267
function_pointer_restrictionst::restrictionst function_pointer_restrictionst::
267268
parse_function_pointer_restrictions_from_command_line(
268-
const std::list<std::string> &restriction_opts)
269+
const std::list<std::string> &restriction_opts,
270+
const goto_modelt &goto_model)
269271
{
270272
return parse_function_pointer_restrictions(
271-
restriction_opts, "--" RESTRICT_FUNCTION_POINTER_OPT);
273+
restriction_opts, "--" RESTRICT_FUNCTION_POINTER_OPT, goto_model);
272274
}
273275

274276
function_pointer_restrictionst::restrictionst
@@ -292,7 +294,8 @@ function_pointer_restrictionst::parse_function_pointer_restrictions_from_file(
292294
function_pointer_restrictionst::restrictiont
293295
function_pointer_restrictionst::parse_function_pointer_restriction(
294296
const std::string &restriction_opt,
295-
const std::string &option)
297+
const std::string &option,
298+
const goto_modelt &goto_model)
296299
{
297300
// the format for restrictions is <pointer_name>/<target[,more_targets]*>
298301
// exactly one pointer and at least one target
@@ -321,7 +324,50 @@ function_pointer_restrictionst::parse_function_pointer_restriction(
321324
"couldn't find target name before '/' in `" + restriction_opt + "'"};
322325
}
323326

324-
auto const pointer_name = restriction_opt.substr(0, pointer_name_end);
327+
auto pointer_name = restriction_opt.substr(0, pointer_name_end);
328+
const auto last_dot = pointer_name.rfind('.');
329+
if(
330+
last_dot != std::string::npos && last_dot + 1 != pointer_name.size() &&
331+
!isdigit(pointer_name[last_dot + 1]))
332+
{
333+
const auto function_id = pointer_name.substr(0, last_dot);
334+
const auto label = pointer_name.substr(last_dot + 1);
335+
336+
bool found = false;
337+
const auto it = goto_model.goto_functions.function_map.find(function_id);
338+
if(it != goto_model.goto_functions.function_map.end())
339+
{
340+
for(const auto &instruction : it->second.body.instructions)
341+
{
342+
if(!instruction.is_function_call())
343+
continue;
344+
345+
const auto &called_function = instruction.call_function();
346+
if(called_function.id() != ID_dereference)
347+
continue;
348+
349+
if(
350+
std::find(
351+
instruction.labels.begin(), instruction.labels.end(), label) !=
352+
instruction.labels.end())
353+
{
354+
auto const &called_function_pointer =
355+
to_dereference_expr(called_function).pointer();
356+
pointer_name =
357+
id2string(to_symbol_expr(called_function_pointer).get_identifier());
358+
found = true;
359+
break;
360+
}
361+
}
362+
}
363+
if(!found)
364+
{
365+
throw invalid_restriction_exceptiont{"non-existent pointer name " +
366+
pointer_name,
367+
restriction_format_message};
368+
}
369+
}
370+
325371
auto const target_names_substring =
326372
restriction_opt.substr(pointer_name_end + 1);
327373
auto const target_name_strings = split_string(target_names_substring, ',');
@@ -405,7 +451,8 @@ function_pointer_restrictionst function_pointer_restrictionst::from_options(
405451
try
406452
{
407453
commandline_restrictions =
408-
parse_function_pointer_restrictions_from_command_line(restriction_opts);
454+
parse_function_pointer_restrictions_from_command_line(
455+
restriction_opts, goto_model);
409456
typecheck_function_pointer_restrictions(
410457
goto_model, commandline_restrictions);
411458
}
@@ -549,7 +596,9 @@ function_pointer_restrictionst::get_function_pointer_by_name_restrictions(
549596
{
550597
function_pointer_restrictionst::restrictionst by_name_restrictions =
551598
parse_function_pointer_restrictions(
552-
restriction_name_opts, "--" RESTRICT_FUNCTION_POINTER_BY_NAME_OPT);
599+
restriction_name_opts,
600+
"--" RESTRICT_FUNCTION_POINTER_BY_NAME_OPT,
601+
goto_model);
553602

554603
function_pointer_restrictionst::restrictionst restrictions;
555604
for(auto const &goto_function : goto_model.goto_functions.function_map)

src/goto-programs/restrict_function_pointers.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,15 +115,18 @@ class function_pointer_restrictionst
115115
message_handlert &message_handler);
116116

117117
static restrictionst parse_function_pointer_restrictions_from_command_line(
118-
const std::list<std::string> &restriction_opts);
118+
const std::list<std::string> &restriction_opts,
119+
const goto_modelt &goto_model);
119120

120121
static restrictionst parse_function_pointer_restrictions(
121122
const std::list<std::string> &restriction_opts,
122-
const std::string &option);
123+
const std::string &option,
124+
const goto_modelt &goto_model);
123125

124126
static restrictiont parse_function_pointer_restriction(
125127
const std::string &restriction_opt,
126-
const std::string &option);
128+
const std::string &option,
129+
const goto_modelt &goto_model);
127130

128131
static optionalt<restrictiont> get_by_name_restriction(
129132
const goto_functiont &goto_function,

unit/goto-programs/restrict_function_pointers.cpp

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,47 +24,53 @@ class fp_restrictionst : public function_pointer_restrictionst
2424

2525
void restriction_parsing_test()
2626
{
27+
goto_modelt goto_model;
28+
2729
{
2830
const auto res = fp_restrictionst::parse_function_pointer_restriction(
29-
"func1/func2", "test");
31+
"func1/func2", "test", goto_model);
3032
REQUIRE(res.first == "func1");
3133
REQUIRE(res.second.size() == 1);
3234
REQUIRE(res.second.find("func2") != res.second.end());
3335
}
3436

3537
{
3638
const auto res = fp_restrictionst::parse_function_pointer_restriction(
37-
"func1/func2,func3", "test");
39+
"func1/func2,func3", "test", goto_model);
3840
REQUIRE(res.first == "func1");
3941
REQUIRE(res.second.size() == 2);
4042
REQUIRE(res.second.find("func2") != res.second.end());
4143
REQUIRE(res.second.find("func3") != res.second.end());
4244
}
4345

4446
REQUIRE_THROWS_AS(
45-
fp_restrictionst::parse_function_pointer_restriction("func", "test"),
47+
fp_restrictionst::parse_function_pointer_restriction(
48+
"func", "test", goto_model),
4649
fp_restrictionst::invalid_restriction_exceptiont);
4750

4851
REQUIRE_THROWS_AS(
49-
fp_restrictionst::parse_function_pointer_restriction("/func", "test"),
52+
fp_restrictionst::parse_function_pointer_restriction(
53+
"/func", "test", goto_model),
5054
fp_restrictionst::invalid_restriction_exceptiont);
5155

5256
REQUIRE_THROWS_AS(
53-
fp_restrictionst::parse_function_pointer_restriction("func/", "test"),
57+
fp_restrictionst::parse_function_pointer_restriction(
58+
"func/", "test", goto_model),
5459
fp_restrictionst::invalid_restriction_exceptiont);
5560

5661
REQUIRE_THROWS_AS(
57-
fp_restrictionst::parse_function_pointer_restriction("func/,", "test"),
62+
fp_restrictionst::parse_function_pointer_restriction(
63+
"func/,", "test", goto_model),
5864
fp_restrictionst::invalid_restriction_exceptiont);
5965

6066
REQUIRE_THROWS_AS(
6167
fp_restrictionst::parse_function_pointer_restriction(
62-
"func1/func2,", "test"),
68+
"func1/func2,", "test", goto_model),
6369
fp_restrictionst::invalid_restriction_exceptiont);
6470

6571
REQUIRE_THROWS_AS(
6672
fp_restrictionst::parse_function_pointer_restriction(
67-
"func1/,func2", "test"),
73+
"func1/,func2", "test", goto_model),
6874
fp_restrictionst::invalid_restriction_exceptiont);
6975
}
7076

0 commit comments

Comments
 (0)