Skip to content

Commit 8266009

Browse files
Map function pointer parameter to function pointer argument
Add mapping from function pointer argument names to local variable names of the harness so users can specify properties of arguments in terms of the names of the arguments rather than having to rely on internal implementation details of the function harness.
1 parent 555fcbe commit 8266009

File tree

2 files changed

+73
-1
lines changed

2 files changed

+73
-1
lines changed

regression/goto-harness/function_pointer_nullable/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
CORE
22
test.c
3-
--harness-type call-function --function entry_point --function-pointer-can-be-null __goto_harness::f_but_may_be_null
3+
--harness-type call-function --function entry_point --function-pointer-can-be-null entry_point::f_but_may_be_null
44
^EXIT=10$
55
^SIGNAL=0$
66
\[entry_point.assertion.1\] line \d+ assertion f != \(void \*\)0: SUCCESS

src/goto-harness/function_call_harness_generator.cpp

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Author: Diffblue Ltd.
1212
#include <util/arith_tools.h>
1313
#include <util/c_types.h>
1414
#include <util/exception_utils.h>
15+
#include <util/prefix.h>
1516
#include <util/std_code.h>
1617
#include <util/std_expr.h>
1718
#include <util/string2int.h>
@@ -80,6 +81,16 @@ struct function_call_harness_generatort::implt
8081
void call_function(
8182
const code_function_callt::argumentst &arguments,
8283
code_blockt &function_body);
84+
/// For function parameters that are pointers to functions we want to
85+
/// be able to specify whether or not they can be NULL. To disambiguate
86+
/// this specification from that for a global variable of the same name,
87+
/// we prepend the name of the function to the parameter name. However,
88+
/// what is actually being initialised in the implementation is not the
89+
/// parameter itself, but a corresponding function argument (local variable
90+
/// of the harness function). We need a mapping from function parameter
91+
/// name to function argument names, and this is what this function does.
92+
std::unordered_set<irep_idt>
93+
map_function_parameters_to_function_argument_names();
8394
};
8495

8596
function_call_harness_generatort::function_call_harness_generatort(
@@ -226,6 +237,8 @@ void function_call_harness_generatort::implt::generate(
226237
recursive_initialization_config.variables_that_hold_array_sizes.insert(
227238
pair.second);
228239
}
240+
recursive_initialization_config.potential_null_function_pointers =
241+
map_function_parameters_to_function_argument_names();
229242
recursive_initialization_config.pointers_to_treat_as_cstrings =
230243
function_arguments_to_treat_as_cstrings;
231244
recursive_initialization = util_make_unique<recursive_initializationt>(
@@ -346,6 +359,43 @@ void function_call_harness_generatort::validate_options(
346359
}
347360
}
348361
}
362+
363+
const namespacet ns{goto_model.symbol_table};
364+
365+
// Make sure all function pointers that the user asks are nullable are
366+
// present in the symbol table.
367+
for(const auto &nullable :
368+
p_impl->recursive_initialization_config.potential_null_function_pointers)
369+
{
370+
const auto &function_pointer_symbol_pointer =
371+
goto_model.symbol_table.lookup(nullable);
372+
373+
if(function_pointer_symbol_pointer == nullptr)
374+
{
375+
throw invalid_command_line_argument_exceptiont{
376+
"nullable function pointer `" + id2string(nullable) +
377+
"' not found in symbol table",
378+
"--" COMMON_HARNESS_GENERATOR_FUNCTION_POINTER_CAN_BE_NULL_OPT};
379+
}
380+
381+
const auto &function_pointer_type =
382+
ns.follow(function_pointer_symbol_pointer->type);
383+
384+
if(!can_cast_type<pointer_typet>(function_pointer_type))
385+
{
386+
throw invalid_command_line_argument_exceptiont{
387+
"`" + id2string(nullable) + "' is not a pointer",
388+
"--" COMMON_HARNESS_GENERATOR_FUNCTION_POINTER_CAN_BE_NULL_OPT};
389+
}
390+
391+
if(!can_cast_type<code_typet>(
392+
to_pointer_type(function_pointer_type).subtype()))
393+
{
394+
throw invalid_command_line_argument_exceptiont{
395+
"`" + id2string(nullable) + "' is not pointing to a function",
396+
"--" COMMON_HARNESS_GENERATOR_FUNCTION_POINTER_CAN_BE_NULL_OPT};
397+
}
398+
}
349399
}
350400

351401
const symbolt &
@@ -490,3 +540,25 @@ void function_call_harness_generatort::implt::call_function(
490540

491541
function_body.add(std::move(function_call));
492542
}
543+
544+
std::unordered_set<irep_idt> function_call_harness_generatort::implt::
545+
map_function_parameters_to_function_argument_names()
546+
{
547+
std::unordered_set<irep_idt> nullables;
548+
for(const auto &nullable :
549+
recursive_initialization_config.potential_null_function_pointers)
550+
{
551+
const auto &nullable_name = id2string(nullable);
552+
const auto &function_prefix = id2string(function) + "::";
553+
if(has_prefix(nullable_name, function_prefix))
554+
{
555+
nullables.insert(
556+
"__goto_harness::" + nullable_name.substr(function_prefix.size()));
557+
}
558+
else
559+
{
560+
nullables.insert(nullable_name);
561+
}
562+
}
563+
return nullables;
564+
}

0 commit comments

Comments
 (0)