28 template <
typename Handler,
typename GotoFunctionT>
29 void for_each_function_call(GotoFunctionT &&goto_function, Handler handler)
31 using targett = decltype(goto_function.body.instructions.begin());
34 [](targett target) {
return target->is_function_call(); },
38 static void restrict_function_pointer(
54 const auto &original_function = location->call_function();
61 auto const &called_function_pointer =
64 auto const &pointer_symbol =
to_symbol_expr(called_function_pointer);
65 auto const restriction_iterator =
66 restrictions.
restrictions.find(pointer_symbol.get_identifier());
68 if(restriction_iterator == restrictions.
restrictions.end())
72 std::unordered_set<symbol_exprt, irep_hash> candidates;
73 for(
const auto &candidate : restriction_iterator->second)
74 candidates.insert(ns.lookup(candidate).symbol_expr());
88 std::string correct_format)
90 correct_format(std::move(correct_format))
98 res +=
"Invalid restriction";
99 res +=
"\nReason: " +
reason;
115 auto const function_pointer_sym =
117 if(function_pointer_sym ==
nullptr)
120 " not found in the symbol table"};
122 auto const &function_pointer_type = function_pointer_sym->type;
123 if(function_pointer_type.id() != ID_pointer)
128 auto const &function_type =
130 if(function_type.id() != ID_code)
136 for(
auto const &function_pointer_target : restriction.second)
138 auto const function_pointer_target_sym =
140 if(function_pointer_target_sym ==
nullptr)
143 "symbol not found: " +
id2string(function_pointer_target)};
145 auto const &function_pointer_target_type =
146 function_pointer_target_sym->type;
147 if(function_pointer_target_type.id() != ID_code)
150 "not a function: " +
id2string(function_pointer_target)};
160 "type mismatch: `" +
id2string(restriction.first) +
"' points to `" +
161 type2c(function_type, ns) +
"', but restriction `" +
162 id2string(function_pointer_target) +
"' has type `" +
163 type2c(function_pointer_target_type, ns) +
"'"};
175 options, goto_model, message_handler);
184 restrict_function_pointer(
228 for(
auto const &restriction : rhs)
230 auto emplace_result = result.emplace(restriction.first, restriction.second);
231 if(!emplace_result.second)
233 for(
auto const &target : restriction.second)
235 emplace_result.first->second.insert(target);
245 const std::list<std::string> &restriction_opts,
246 const std::string &option,
249 auto function_pointer_restrictions =
252 for(
const std::string &restriction_opt : restriction_opts)
254 const auto restriction =
257 const bool inserted = function_pointer_restrictions
258 .emplace(restriction.first, restriction.second)
264 "function pointer restriction for `" +
id2string(restriction.first) +
265 "' was specified twice"};
269 return function_pointer_restrictions;
274 const std::list<std::string> &restriction_opts,
283 const std::list<std::string> &filenames,
289 for(
auto const &filename : filenames)
295 std::move(merged_restrictions),
restrictions.restrictions);
298 return merged_restrictions;
306 const std::string &candidate,
309 const auto last_dot = candidate.rfind(
'.');
311 last_dot == std::string::npos || last_dot + 1 == candidate.size() ||
312 isdigit(candidate[last_dot + 1]))
317 std::string pointer_name = candidate;
319 const auto function_id = pointer_name.substr(0, last_dot);
320 const auto label = pointer_name.substr(last_dot + 1);
327 for(
const auto &instruction : it->second.body.instructions)
331 instruction.labels.begin(), instruction.labels.end(), label) !=
332 instruction.labels.end())
334 location = instruction.source_location();
338 instruction.is_function_call() &&
339 instruction.call_function().id() == ID_dereference &&
340 location.has_value() && instruction.source_location() == *location)
342 auto const &called_function_pointer =
354 "non-existent pointer name " + pointer_name,
355 "pointers should be identifiers or <function_name>.<label>"};
363 const std::string &restriction_opt,
364 const std::string &option,
369 auto const pointer_name_end = restriction_opt.find(
'/');
370 auto const restriction_format_message =
371 "the format for restrictions is "
372 "<pointer_name>/<target[,more_targets]*>";
374 if(pointer_name_end == std::string::npos)
377 restriction_opt +
"'",
378 restriction_format_message};
381 if(pointer_name_end == restriction_opt.size())
384 "couldn't find names of targets after '/' in `" + restriction_opt +
"'",
385 restriction_format_message};
388 if(pointer_name_end == 0)
391 "couldn't find target name before '/' in `" + restriction_opt +
"'"};
395 restriction_opt.substr(0, pointer_name_end), goto_model);
397 auto const target_names_substring =
398 restriction_opt.substr(pointer_name_end + 1);
399 auto const target_name_strings =
split_string(target_names_substring,
',');
401 if(target_name_strings.size() == 1 && target_name_strings[0].empty())
404 "missing target list for function pointer restriction " + pointer_name,
405 restriction_format_message};
408 std::unordered_set<irep_idt> target_names;
409 target_names.insert(target_name_strings.begin(), target_name_strings.end());
411 for(
auto const &target_name : target_names)
413 if(target_name == ID_empty_string)
416 "leading or trailing comma in restrictions for `" + pointer_name +
"'",
417 restriction_format_message);
421 return std::make_pair(pointer_name, target_names);
432 const exprt &
function = location->call_function();
441 auto const &function_pointer_call_site =
448 function_pointer_call_site.get_identifier(),
449 "called function pointer must have been assigned at the previous location");
456 const auto restriction = by_name_restrictions.find(rhs.get_identifier());
458 if(restriction != by_name_restrictions.end())
462 function_pointer_call_site.get_identifier(), restriction->second));
473 auto const restriction_opts =
479 commandline_restrictions =
481 restriction_opts, goto_model);
483 goto_model, commandline_restrictions);
496 auto const restriction_file_opts =
499 restriction_file_opts, goto_model, message_handler);
510 auto const restriction_name_opts =
513 restriction_name_opts, goto_model);
525 commandline_restrictions,
535 if(!
json.is_object())
542 std::string pointer_name =
545 if(!restriction.second.is_array())
547 throw deserialization_exceptiont{
"Value of " + restriction.first +
550 auto possible_targets = std::unordered_set<irep_idt>{};
555 std::inserter(possible_targets, possible_targets.end()),
556 [&](
const jsont &array_element) {
557 if(!array_element.is_string())
559 throw deserialization_exceptiont{
560 "Value of " + restriction.first +
561 "contains a non-string array element"};
563 return irep_idt{to_json_string(array_element).value};
565 return possible_targets;
573 const std::string &filename,
577 auto inFile = std::ifstream{filename};
583 "failed to read function pointer restrictions from " + filename};
591 auto function_pointer_restrictions_json =
jsont{};
592 auto &restrictions_json_object =
597 auto &targets_array =
599 for(
auto const &target : restriction.second)
605 return function_pointer_restrictions_json;
609 const std::string &filename)
const
611 auto function_pointer_restrictions_json =
to_json();
613 auto outFile = std::ofstream{filename};
618 " for writing function pointer restrictions"};
621 function_pointer_restrictions_json.output(outFile);
628 const std::list<std::string> &restriction_name_opts,
633 restriction_name_opts,
640 for_each_function_call(
642 const auto restriction = get_by_name_restriction(
643 goto_function.second, by_name_restrictions, it);
647 restrictions.insert(*restriction);