Skip to content

Commit 60d3466

Browse files
authored
Merge pull request #6610 from tautschnig/bugfixes/6609-restrictions-json
Function pointer restrictions: support labels in JSON input
2 parents 42703f4 + 73980e4 commit 60d3466

File tree

6 files changed

+128
-85
lines changed

6 files changed

+128
-85
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
CORE
2+
test.c
3+
--function-pointer-restrictions-file restriction.json
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, with the
11+
restriction described in the JSON file instead of the command-line directly.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"use_f.labelled_call":[
3+
"f"
4+
]
5+
}

src/goto-instrument/goto_instrument_parse_options.cpp

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1029,12 +1029,7 @@ void goto_instrument_parse_optionst::instrument_goto_program()
10291029
{
10301030
label_function_pointer_call_sites(goto_model);
10311031

1032-
const auto function_pointer_restrictions =
1033-
function_pointer_restrictionst::from_options(
1034-
options, goto_model, log.get_message_handler());
1035-
1036-
restrict_function_pointers(
1037-
ui_message_handler, goto_model, function_pointer_restrictions);
1032+
restrict_function_pointers(ui_message_handler, goto_model, options);
10381033
}
10391034
}
10401035

src/goto-programs/restrict_function_pointers.cpp

Lines changed: 84 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -84,14 +84,14 @@ static void restrict_function_pointer(
8484
}
8585
} // namespace
8686

87-
function_pointer_restrictionst::invalid_restriction_exceptiont::
88-
invalid_restriction_exceptiont(std::string reason, std::string correct_format)
87+
invalid_restriction_exceptiont::invalid_restriction_exceptiont(
88+
std::string reason,
89+
std::string correct_format)
8990
: reason(std::move(reason)), correct_format(std::move(correct_format))
9091
{
9192
}
9293

93-
std::string
94-
function_pointer_restrictionst::invalid_restriction_exceptiont::what() const
94+
std::string invalid_restriction_exceptiont::what() const
9595
{
9696
std::string res;
9797

@@ -169,8 +169,13 @@ void function_pointer_restrictionst::typecheck_function_pointer_restrictions(
169169
void restrict_function_pointers(
170170
message_handlert &message_handler,
171171
goto_modelt &goto_model,
172-
const function_pointer_restrictionst &restrictions)
172+
const optionst &options)
173173
{
174+
const auto restrictions = function_pointer_restrictionst::from_options(
175+
options, goto_model, message_handler);
176+
if(restrictions.restrictions.empty())
177+
return;
178+
174179
for(auto &function_item : goto_model.goto_functions.function_map)
175180
{
176181
goto_functiont &goto_function = function_item.second;
@@ -276,13 +281,15 @@ function_pointer_restrictionst::restrictionst function_pointer_restrictionst::
276281
function_pointer_restrictionst::restrictionst
277282
function_pointer_restrictionst::parse_function_pointer_restrictions_from_file(
278283
const std::list<std::string> &filenames,
284+
const goto_modelt &goto_model,
279285
message_handlert &message_handler)
280286
{
281287
auto merged_restrictions = function_pointer_restrictionst::restrictionst{};
282288

283289
for(auto const &filename : filenames)
284290
{
285-
auto const restrictions = read_from_file(filename, message_handler);
291+
auto const restrictions =
292+
read_from_file(filename, goto_model, message_handler);
286293

287294
merged_restrictions = merge_function_pointer_restrictions(
288295
std::move(merged_restrictions), restrictions.restrictions);
@@ -291,6 +298,66 @@ function_pointer_restrictionst::parse_function_pointer_restrictions_from_file(
291298
return merged_restrictions;
292299
}
293300

301+
/// Parse \p candidate to distinguish whether it refers to a function pointer
302+
/// symbol directly (as produced by \ref label_function_pointer_call_sites), or
303+
/// a source location via its statement label. In the latter case, resolve the
304+
/// name to the underlying function pointer symbol.
305+
static std::string resolve_pointer_name(
306+
const std::string &candidate,
307+
const goto_modelt &goto_model)
308+
{
309+
const auto last_dot = candidate.rfind('.');
310+
if(
311+
last_dot == std::string::npos || last_dot + 1 == candidate.size() ||
312+
isdigit(candidate[last_dot + 1]))
313+
{
314+
return candidate;
315+
}
316+
317+
std::string pointer_name = candidate;
318+
319+
const auto function_id = pointer_name.substr(0, last_dot);
320+
const auto label = pointer_name.substr(last_dot + 1);
321+
322+
bool found = false;
323+
const auto it = goto_model.goto_functions.function_map.find(function_id);
324+
if(it != goto_model.goto_functions.function_map.end())
325+
{
326+
optionalt<source_locationt> location;
327+
for(const auto &instruction : it->second.body.instructions)
328+
{
329+
if(
330+
std::find(
331+
instruction.labels.begin(), instruction.labels.end(), label) !=
332+
instruction.labels.end())
333+
{
334+
location = instruction.source_location();
335+
}
336+
337+
if(
338+
instruction.is_function_call() &&
339+
instruction.call_function().id() == ID_dereference &&
340+
location.has_value() && instruction.source_location() == *location)
341+
{
342+
auto const &called_function_pointer =
343+
to_dereference_expr(instruction.call_function()).pointer();
344+
pointer_name =
345+
id2string(to_symbol_expr(called_function_pointer).get_identifier());
346+
found = true;
347+
break;
348+
}
349+
}
350+
}
351+
if(!found)
352+
{
353+
throw invalid_restriction_exceptiont{
354+
"non-existent pointer name " + pointer_name,
355+
"pointers should be identifiers or <function_name>.<label>"};
356+
}
357+
358+
return pointer_name;
359+
}
360+
294361
function_pointer_restrictionst::restrictiont
295362
function_pointer_restrictionst::parse_function_pointer_restriction(
296363
const std::string &restriction_opt,
@@ -324,51 +391,8 @@ function_pointer_restrictionst::parse_function_pointer_restriction(
324391
"couldn't find target name before '/' in `" + restriction_opt + "'"};
325392
}
326393

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-
}
394+
std::string pointer_name = resolve_pointer_name(
395+
restriction_opt.substr(0, pointer_name_end), goto_model);
372396

373397
auto const target_names_substring =
374398
restriction_opt.substr(pointer_name_end + 1);
@@ -470,7 +494,7 @@ function_pointer_restrictionst function_pointer_restrictionst::from_options(
470494
auto const restriction_file_opts =
471495
options.get_list_option(RESTRICT_FUNCTION_POINTER_FROM_FILE_OPT);
472496
file_restrictions = parse_function_pointer_restrictions_from_file(
473-
restriction_file_opts, message_handler);
497+
restriction_file_opts, goto_model, message_handler);
474498
typecheck_function_pointer_restrictions(goto_model, file_restrictions);
475499
}
476500
catch(const invalid_restriction_exceptiont &e)
@@ -498,8 +522,9 @@ function_pointer_restrictionst function_pointer_restrictionst::from_options(
498522
merge_function_pointer_restrictions(file_restrictions, name_restrictions))};
499523
}
500524

501-
function_pointer_restrictionst
502-
function_pointer_restrictionst::from_json(const jsont &json)
525+
function_pointer_restrictionst function_pointer_restrictionst::from_json(
526+
const jsont &json,
527+
const goto_modelt &goto_model)
503528
{
504529
function_pointer_restrictionst::restrictionst restrictions;
505530

@@ -510,7 +535,9 @@ function_pointer_restrictionst::from_json(const jsont &json)
510535

511536
for(auto const &restriction : to_json_object(json))
512537
{
513-
restrictions.emplace(irep_idt{restriction.first}, [&] {
538+
std::string pointer_name =
539+
resolve_pointer_name(restriction.first, goto_model);
540+
restrictions.emplace(irep_idt{pointer_name}, [&] {
514541
if(!restriction.second.is_array())
515542
{
516543
throw deserialization_exceptiont{"Value of " + restriction.first +
@@ -540,6 +567,7 @@ function_pointer_restrictionst::from_json(const jsont &json)
540567

541568
function_pointer_restrictionst function_pointer_restrictionst::read_from_file(
542569
const std::string &filename,
570+
const goto_modelt &goto_model,
543571
message_handlert &message_handler)
544572
{
545573
auto inFile = std::ifstream{filename};
@@ -551,7 +579,7 @@ function_pointer_restrictionst function_pointer_restrictionst::read_from_file(
551579
"failed to read function pointer restrictions from " + filename};
552580
}
553581

554-
return from_json(json);
582+
return from_json(json, goto_model);
555583
}
556584

557585
jsont function_pointer_restrictionst::to_json() const

src/goto-programs/restrict_function_pointers.h

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,19 @@ void parse_function_pointer_restriction_options_from_cmdline(
6464
const cmdlinet &cmdline,
6565
optionst &options);
6666

67+
class invalid_restriction_exceptiont : public cprover_exception_baset
68+
{
69+
public:
70+
explicit invalid_restriction_exceptiont(
71+
std::string reason,
72+
std::string correct_format = "");
73+
74+
std::string what() const override;
75+
76+
std::string reason;
77+
std::string correct_format;
78+
};
79+
6780
class function_pointer_restrictionst
6881
{
6982
public:
@@ -80,28 +93,17 @@ class function_pointer_restrictionst
8093
message_handlert &message_handler);
8194

8295
jsont to_json() const;
83-
static function_pointer_restrictionst from_json(const jsont &json);
96+
static function_pointer_restrictionst
97+
from_json(const jsont &json, const goto_modelt &goto_model);
8498

8599
static function_pointer_restrictionst read_from_file(
86100
const std::string &filename,
101+
const goto_modelt &goto_model,
87102
message_handlert &message_handler);
88103

89104
void write_to_file(const std::string &filename) const;
90105

91106
protected:
92-
class invalid_restriction_exceptiont : public cprover_exception_baset
93-
{
94-
public:
95-
explicit invalid_restriction_exceptiont(
96-
std::string reason,
97-
std::string correct_format = "");
98-
99-
std::string what() const override;
100-
101-
std::string reason;
102-
std::string correct_format;
103-
};
104-
105107
static void typecheck_function_pointer_restrictions(
106108
const goto_modelt &goto_model,
107109
const restrictionst &restrictions);
@@ -112,6 +114,7 @@ class function_pointer_restrictionst
112114

113115
static restrictionst parse_function_pointer_restrictions_from_file(
114116
const std::list<std::string> &filenames,
117+
const goto_modelt &goto_model,
115118
message_handlert &message_handler);
116119

117120
static restrictionst parse_function_pointer_restrictions_from_command_line(
@@ -161,6 +164,6 @@ class function_pointer_restrictionst
161164
void restrict_function_pointers(
162165
message_handlert &message_handler,
163166
goto_modelt &goto_model,
164-
const function_pointer_restrictionst &restrictions);
167+
const optionst &options);
165168

166169
#endif // CPROVER_GOTO_PROGRAMS_RESTRICT_FUNCTION_POINTERS_H

unit/goto-programs/restrict_function_pointers.cpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,32 +46,32 @@ void restriction_parsing_test()
4646
REQUIRE_THROWS_AS(
4747
fp_restrictionst::parse_function_pointer_restriction(
4848
"func", "test", goto_model),
49-
fp_restrictionst::invalid_restriction_exceptiont);
49+
invalid_restriction_exceptiont);
5050

5151
REQUIRE_THROWS_AS(
5252
fp_restrictionst::parse_function_pointer_restriction(
5353
"/func", "test", goto_model),
54-
fp_restrictionst::invalid_restriction_exceptiont);
54+
invalid_restriction_exceptiont);
5555

5656
REQUIRE_THROWS_AS(
5757
fp_restrictionst::parse_function_pointer_restriction(
5858
"func/", "test", goto_model),
59-
fp_restrictionst::invalid_restriction_exceptiont);
59+
invalid_restriction_exceptiont);
6060

6161
REQUIRE_THROWS_AS(
6262
fp_restrictionst::parse_function_pointer_restriction(
6363
"func/,", "test", goto_model),
64-
fp_restrictionst::invalid_restriction_exceptiont);
64+
invalid_restriction_exceptiont);
6565

6666
REQUIRE_THROWS_AS(
6767
fp_restrictionst::parse_function_pointer_restriction(
6868
"func1/func2,", "test", goto_model),
69-
fp_restrictionst::invalid_restriction_exceptiont);
69+
invalid_restriction_exceptiont);
7070

7171
REQUIRE_THROWS_AS(
7272
fp_restrictionst::parse_function_pointer_restriction(
7373
"func1/,func2", "test", goto_model),
74-
fp_restrictionst::invalid_restriction_exceptiont);
74+
invalid_restriction_exceptiont);
7575
}
7676

7777
void merge_restrictions_test()
@@ -250,6 +250,7 @@ TEST_CASE("Json conversion", "[core]")
250250
// representation for the same restrictions can differ, due to the array
251251
// elements appearing in different orders)
252252

253+
goto_modelt goto_model;
253254
std::istringstream ss(
254255
"{"
255256
" \"use_f.function_pointer_call.1\": [\"f\", \"g\"],"
@@ -262,7 +263,7 @@ TEST_CASE("Json conversion", "[core]")
262263

263264
// json1 -> restrictions1
264265
const auto function_pointer_restrictions1 =
265-
function_pointer_restrictionst::from_json(json1);
266+
function_pointer_restrictionst::from_json(json1, goto_model);
266267

267268
const auto &restrictions = function_pointer_restrictions1.restrictions;
268269

@@ -284,7 +285,7 @@ TEST_CASE("Json conversion", "[core]")
284285

285286
// json2 -> restrictions2
286287
const auto function_pointer_restrictions2 =
287-
function_pointer_restrictionst::from_json(json2);
288+
function_pointer_restrictionst::from_json(json2, goto_model);
288289

289290
REQUIRE(
290291
function_pointer_restrictions1.restrictions ==

0 commit comments

Comments
 (0)