Skip to content

Commit bb617bb

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 860117d commit bb617bb

File tree

5 files changed

+168
-38
lines changed

5 files changed

+168
-38
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\]: 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/cbmc/cbmc_parse_options.cpp

Lines changed: 36 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ Author: Daniel Kroening, [email protected]
1111

1212
#include "cbmc_parse_options.h"
1313

14-
#include <fstream>
1514
#include <cstdlib> // exit()
15+
#include <fstream>
1616
#include <iostream>
1717
#include <memory>
1818

@@ -178,8 +178,9 @@ void cbmc_parse_optionst::get_command_line_options(optionst &options)
178178
exit(CPROVER_EXIT_USAGE_ERROR);
179179
}
180180

181-
if(cmdline.isset("reachability-slice") &&
182-
cmdline.isset("reachability-slice-fb"))
181+
if(
182+
cmdline.isset("reachability-slice") &&
183+
cmdline.isset("reachability-slice-fb"))
183184
{
184185
log.error()
185186
<< "--reachability-slice and --reachability-slice-fb must not be "
@@ -258,9 +259,9 @@ void cbmc_parse_optionst::get_command_line_options(optionst &options)
258259
if(cmdline.isset("no-simplify"))
259260
options.set_option("simplify", false);
260261

261-
if(cmdline.isset("stop-on-fail") ||
262-
cmdline.isset("dimacs") ||
263-
cmdline.isset("outfile"))
262+
if(
263+
cmdline.isset("stop-on-fail") || cmdline.isset("dimacs") ||
264+
cmdline.isset("outfile"))
264265
options.set_option("stop-on-fail", true);
265266

266267
if(
@@ -370,8 +371,7 @@ void cbmc_parse_optionst::get_command_line_options(optionst &options)
370371

371372
if(cmdline.isset("max-node-refinement"))
372373
options.set_option(
373-
"max-node-refinement",
374-
cmdline.get_value("max-node-refinement"));
374+
"max-node-refinement", cmdline.get_value("max-node-refinement"));
375375

376376
// SMT Options
377377

@@ -387,11 +387,11 @@ void cbmc_parse_optionst::get_command_line_options(optionst &options)
387387
if(cmdline.isset("fpa"))
388388
options.set_option("fpa", true);
389389

390-
bool solver_set=false;
390+
bool solver_set = false;
391391

392392
if(cmdline.isset("boolector"))
393393
{
394-
options.set_option("boolector", true), solver_set=true;
394+
options.set_option("boolector", true), solver_set = true;
395395
options.set_option("smt2", true);
396396
}
397397

@@ -403,25 +403,25 @@ void cbmc_parse_optionst::get_command_line_options(optionst &options)
403403

404404
if(cmdline.isset("mathsat"))
405405
{
406-
options.set_option("mathsat", true), solver_set=true;
406+
options.set_option("mathsat", true), solver_set = true;
407407
options.set_option("smt2", true);
408408
}
409409

410410
if(cmdline.isset("cvc4"))
411411
{
412-
options.set_option("cvc4", true), solver_set=true;
412+
options.set_option("cvc4", true), solver_set = true;
413413
options.set_option("smt2", true);
414414
}
415415

416416
if(cmdline.isset("yices"))
417417
{
418-
options.set_option("yices", true), solver_set=true;
418+
options.set_option("yices", true), solver_set = true;
419419
options.set_option("smt2", true);
420420
}
421421

422422
if(cmdline.isset("z3"))
423423
{
424-
options.set_option("z3", true), solver_set=true;
424+
options.set_option("z3", true), solver_set = true;
425425
options.set_option("smt2", true);
426426
}
427427

@@ -461,8 +461,7 @@ void cbmc_parse_optionst::get_command_line_options(optionst &options)
461461
if(cmdline.isset("symex-coverage-report"))
462462
{
463463
options.set_option(
464-
"symex-coverage-report",
465-
cmdline.get_value("symex-coverage-report"));
464+
"symex-coverage-report", cmdline.get_value("symex-coverage-report"));
466465
options.set_option("paths-symex-explore-all", true);
467466
}
468467

@@ -512,8 +511,7 @@ int cbmc_parse_optionst::doit()
512511
// Unwinding of transition systems is done by hw-cbmc.
513512
//
514513

515-
if(cmdline.isset("module") ||
516-
cmdline.isset("gen-interface"))
514+
if(cmdline.isset("module") || cmdline.isset("gen-interface"))
517515
{
518516
log.error() << "This version of CBMC has no support for "
519517
" hardware modules. Please use hw-cbmc."
@@ -552,13 +550,13 @@ int cbmc_parse_optionst::doit()
552550
return CPROVER_EXIT_INCORRECT_TASK;
553551
}
554552

555-
std::string filename=cmdline.args[0];
553+
std::string filename = cmdline.args[0];
556554

557-
#ifdef _MSC_VER
555+
#ifdef _MSC_VER
558556
std::ifstream infile(widen(filename));
559-
#else
557+
#else
560558
std::ifstream infile(filename);
561-
#endif
559+
#endif
562560

563561
if(!infile)
564562
{
@@ -567,10 +565,9 @@ int cbmc_parse_optionst::doit()
567565
return CPROVER_EXIT_INCORRECT_TASK;
568566
}
569567

570-
std::unique_ptr<languaget> language=
571-
get_language_from_filename(filename);
568+
std::unique_ptr<languaget> language = get_language_from_filename(filename);
572569

573-
if(language==nullptr)
570+
if(language == nullptr)
574571
{
575572
log.error() << "failed to figure out type of file '" << filename << "'"
576573
<< messaget::eom;
@@ -595,11 +592,12 @@ int cbmc_parse_optionst::doit()
595592
int get_goto_program_ret =
596593
get_goto_program(goto_model, options, cmdline, ui_message_handler);
597594

598-
if(get_goto_program_ret!=-1)
595+
if(get_goto_program_ret != -1)
599596
return get_goto_program_ret;
600597

601-
if(cmdline.isset("show-claims") || // will go away
602-
cmdline.isset("show-properties")) // use this one
598+
if(
599+
cmdline.isset("show-claims") || // will go away
600+
cmdline.isset("show-properties")) // use this one
603601
{
604602
show_properties(goto_model, ui_message_handler);
605603
return CPROVER_EXIT_SUCCESS;
@@ -840,14 +838,20 @@ bool cbmc_parse_optionst::process_goto_program(
840838
log.status() << "Removal of function pointers and virtual functions"
841839
<< messaget::eom;
842840

843-
const auto function_pointer_restrictions =
844-
function_pointer_restrictionst::from_options(
845-
options, log.get_message_handler());
846-
if(!function_pointer_restrictions.restrictions.empty())
841+
if(
842+
options.is_set(RESTRICT_FUNCTION_POINTER_OPT) ||
843+
options.is_set(RESTRICT_FUNCTION_POINTER_BY_NAME_OPT) ||
844+
options.is_set(RESTRICT_FUNCTION_POINTER_FROM_FILE_OPT))
847845
{
848846
label_function_pointer_call_sites(goto_model);
847+
auto const by_name_restrictions =
848+
get_function_pointer_by_name_restrictions(goto_model, options);
849+
const auto function_pointer_restrictions =
850+
by_name_restrictions.merge(function_pointer_restrictionst::from_options(
851+
options, log.get_message_handler()));
849852
restrict_function_pointers(goto_model, function_pointer_restrictions);
850853
}
854+
851855
remove_function_pointers(
852856
log.get_message_handler(),
853857
goto_model,

src/goto-programs/restrict_function_pointers.cpp

Lines changed: 68 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -108,12 +108,13 @@ source_locationt make_function_pointer_restriction_assertion_source_location(
108108
return source_location;
109109
}
110110

111-
template <typename Handler>
112-
void for_each_function_call(goto_functiont &goto_function, Handler handler)
111+
template <typename Handler, typename GotoFunctionT>
112+
void for_each_function_call(GotoFunctionT &&goto_function, Handler handler)
113113
{
114+
using targett = decltype(goto_function.body.instructions.begin());
114115
for_each_goto_location_if(
115116
goto_function,
116-
[](goto_programt::targett target) { return target->is_function_call(); },
117+
[](targett target) { return target->is_function_call(); },
117118
handler);
118119
}
119120
} // namespace
@@ -210,6 +211,9 @@ void parse_function_pointer_restriction_options_from_cmdline(
210211
options.set_option(
211212
RESTRICT_FUNCTION_POINTER_FROM_FILE_OPT,
212213
cmdline.get_values(RESTRICT_FUNCTION_POINTER_FROM_FILE_OPT));
214+
options.set_option(
215+
RESTRICT_FUNCTION_POINTER_BY_NAME_OPT,
216+
cmdline.get_values(RESTRICT_FUNCTION_POINTER_BY_NAME_OPT));
213217
}
214218

215219
namespace
@@ -236,7 +240,8 @@ merge_function_pointer_restrictions(
236240

237241
function_pointer_restrictionst::restrictionst
238242
parse_function_pointer_restrictions_from_command_line(
239-
const std::list<std::string> &restriction_opts)
243+
const std::list<std::string> &restriction_opts,
244+
const std::string &option_name)
240245
{
241246
auto function_pointer_restrictions =
242247
function_pointer_restrictionst::restrictionst{};
@@ -336,7 +341,8 @@ function_pointer_restrictionst function_pointer_restrictionst::from_options(
336341
auto const restriction_opts =
337342
options.get_list_option(RESTRICT_FUNCTION_POINTER_OPT);
338343
auto const commandline_restrictions =
339-
parse_function_pointer_restrictions_from_command_line(restriction_opts);
344+
parse_function_pointer_restrictions_from_command_line(
345+
restriction_opts, RESTRICT_FUNCTION_POINTER_OPT);
340346
auto const file_restrictions = parse_function_pointer_restrictions_from_file(
341347
options.get_list_option(RESTRICT_FUNCTION_POINTER_FROM_FILE_OPT),
342348
message_handler);
@@ -413,3 +419,60 @@ void function_pointer_restrictionst::write_to_file(
413419
}
414420
function_pointer_restrictions_json.output(outFile);
415421
}
422+
function_pointer_restrictionst function_pointer_restrictionst::merge(
423+
const function_pointer_restrictionst &other) const
424+
{
425+
return function_pointer_restrictionst{
426+
merge_function_pointer_restrictions(restrictions, other.restrictions)};
427+
}
428+
429+
function_pointer_restrictionst get_function_pointer_by_name_restrictions(
430+
const goto_modelt &goto_model,
431+
const optionst &options)
432+
{
433+
function_pointer_restrictionst::restrictionst by_name_restrictions =
434+
parse_function_pointer_restrictions_from_command_line(
435+
options.get_list_option(RESTRICT_FUNCTION_POINTER_BY_NAME_OPT),
436+
RESTRICT_FUNCTION_POINTER_BY_NAME_OPT);
437+
function_pointer_restrictionst::restrictionst restrictions;
438+
for(auto const &goto_function : goto_model.goto_functions.function_map)
439+
{
440+
for_each_function_call(
441+
goto_function.second, [&](goto_programt::const_targett location) {
442+
PRECONDITION(location->is_function_call());
443+
if(can_cast_expr<dereference_exprt>(
444+
location->get_function_call().function()))
445+
{
446+
PRECONDITION(can_cast_expr<symbol_exprt>(
447+
to_dereference_expr(location->get_function_call().function())
448+
.pointer()));
449+
auto const &function_pointer_call_site = to_symbol_expr(
450+
to_dereference_expr(location->get_function_call().function())
451+
.pointer());
452+
auto const &body = goto_function.second.body;
453+
for(auto it = std::prev(location); it != body.instructions.end();
454+
++it)
455+
{
456+
if(
457+
it->is_assign() &&
458+
it->get_assign().lhs() == function_pointer_call_site &&
459+
can_cast_expr<symbol_exprt>(it->get_assign().rhs()))
460+
{
461+
auto const &assign_rhs = to_symbol_expr(it->get_assign().rhs());
462+
auto const restriction =
463+
by_name_restrictions.find(assign_rhs.get_identifier());
464+
if(
465+
restriction != by_name_restrictions.end() &&
466+
restriction->first == assign_rhs.get_identifier())
467+
{
468+
restrictions.emplace(
469+
function_pointer_call_site.get_identifier(),
470+
restriction->second);
471+
}
472+
}
473+
}
474+
}
475+
});
476+
}
477+
return function_pointer_restrictionst{restrictions};
478+
}

src/goto-programs/restrict_function_pointers.h

Lines changed: 10 additions & 1 deletion
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 RESTRICT_FUNCTION_POINTER_HELP \
3943
"--" RESTRICT_FUNCTION_POINTER_OPT \
@@ -70,8 +74,13 @@ struct function_pointer_restrictionst
7074
message_handlert &message_handler);
7175

7276
void write_to_file(const std::string &filename) const;
77+
function_pointer_restrictionst
78+
merge(const function_pointer_restrictionst &other) const;
7379
};
7480

81+
function_pointer_restrictionst get_function_pointer_by_name_restrictions(
82+
const goto_modelt &goto_model,
83+
const optionst &options);
7584
/// Apply a function pointer restrictions to a goto_model. Each restriction is a
7685
/// mapping from a pointer name to a set of possible targets. Replace calls of
7786
/// these "restricted" pointers with a branch on the value of the function

0 commit comments

Comments
 (0)