Skip to content

Commit 771a153

Browse files
committed
Support labels to identify function pointer to be restricted
Function pointer indexes may change as code is modified. Labelling function calls provides for a more stable way of referencing. Fixes: #6464
1 parent 3feb57d commit 771a153

File tree

6 files changed

+123
-21
lines changed

6 files changed

+123
-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: 59 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,52 @@ 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+
optionalt<source_locationt> location;
341+
for(const auto &instruction : it->second.body.instructions)
342+
{
343+
if(
344+
std::find(
345+
instruction.labels.begin(), instruction.labels.end(), label) !=
346+
instruction.labels.end())
347+
{
348+
location = instruction.source_location();
349+
}
350+
351+
if(
352+
instruction.is_function_call() &&
353+
instruction.call_function().id() == ID_dereference &&
354+
location.has_value() && instruction.source_location() == *location)
355+
{
356+
auto const &called_function_pointer =
357+
to_dereference_expr(instruction.call_function()).pointer();
358+
pointer_name =
359+
id2string(to_symbol_expr(called_function_pointer).get_identifier());
360+
found = true;
361+
break;
362+
}
363+
}
364+
}
365+
if(!found)
366+
{
367+
throw invalid_restriction_exceptiont{"non-existent pointer name " +
368+
pointer_name,
369+
restriction_format_message};
370+
}
371+
}
372+
325373
auto const target_names_substring =
326374
restriction_opt.substr(pointer_name_end + 1);
327375
auto const target_name_strings = split_string(target_names_substring, ',');
@@ -405,7 +453,8 @@ function_pointer_restrictionst function_pointer_restrictionst::from_options(
405453
try
406454
{
407455
commandline_restrictions =
408-
parse_function_pointer_restrictions_from_command_line(restriction_opts);
456+
parse_function_pointer_restrictions_from_command_line(
457+
restriction_opts, goto_model);
409458
typecheck_function_pointer_restrictions(
410459
goto_model, commandline_restrictions);
411460
}
@@ -549,7 +598,9 @@ function_pointer_restrictionst::get_function_pointer_by_name_restrictions(
549598
{
550599
function_pointer_restrictionst::restrictionst by_name_restrictions =
551600
parse_function_pointer_restrictions(
552-
restriction_name_opts, "--" RESTRICT_FUNCTION_POINTER_BY_NAME_OPT);
601+
restriction_name_opts,
602+
"--" RESTRICT_FUNCTION_POINTER_BY_NAME_OPT,
603+
goto_model);
553604

554605
function_pointer_restrictionst::restrictionst restrictions;
555606
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)