@@ -12,6 +12,7 @@ Author: Diffblue Ltd.
12
12
#include < util/arith_tools.h>
13
13
#include < util/c_types.h>
14
14
#include < util/exception_utils.h>
15
+ #include < util/prefix.h>
15
16
#include < util/std_code.h>
16
17
#include < util/std_expr.h>
17
18
#include < util/string2int.h>
@@ -72,14 +73,24 @@ struct function_call_harness_generatort::implt
72
73
void ensure_harness_does_not_already_exist ();
73
74
// / Update the goto-model with the new harness function.
74
75
void add_harness_function_to_goto_model (code_blockt function_body);
75
- // / declare local variables for each of the parameters of the entry function
76
+ // / Declare local variables for each of the parameters of the entry function
76
77
// / and return them
77
78
code_function_callt::argumentst declare_arguments (code_blockt &function_body);
78
- // / write initialisation code for each of the arguments into function_body,
79
+ // / Write initialisation code for each of the arguments into function_body,
79
80
// / then insert a call to the entry function with the arguments
80
81
void call_function (
81
82
const code_function_callt::argumentst &arguments,
82
83
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 ();
83
94
};
84
95
85
96
function_call_harness_generatort::function_call_harness_generatort (
@@ -173,6 +184,30 @@ void function_call_harness_generatort::handle_option(
173
184
{
174
185
p_impl->recursive_initialization_config .arguments_may_be_equal = true ;
175
186
}
187
+ else if (option == COMMON_HARNESS_GENERATOR_FUNCTION_POINTER_CAN_BE_NULL_OPT)
188
+ {
189
+ std::transform (
190
+ values.begin (),
191
+ values.end (),
192
+ std::inserter (
193
+ p_impl->recursive_initialization_config
194
+ .potential_null_function_pointers ,
195
+ p_impl->recursive_initialization_config .potential_null_function_pointers
196
+ .end ()),
197
+ [](const std::string &opt) -> irep_idt { return irep_idt{opt}; });
198
+ }
199
+ else if (option == COMMON_HARNESS_GENERATOR_FUNCTION_POINTER_CAN_BE_NULL_OPT)
200
+ {
201
+ std::transform (
202
+ values.begin (),
203
+ values.end (),
204
+ std::inserter (
205
+ p_impl->recursive_initialization_config
206
+ .potential_null_function_pointers ,
207
+ p_impl->recursive_initialization_config .potential_null_function_pointers
208
+ .end ()),
209
+ [](const std::string &opt) -> irep_idt { return irep_idt{opt}; });
210
+ }
176
211
else
177
212
{
178
213
throw invalid_command_line_argument_exceptiont{
@@ -214,6 +249,8 @@ void function_call_harness_generatort::implt::generate(
214
249
recursive_initialization_config.variables_that_hold_array_sizes .insert (
215
250
pair.second );
216
251
}
252
+ recursive_initialization_config.potential_null_function_pointers =
253
+ map_function_parameters_to_function_argument_names ();
217
254
recursive_initialization_config.pointers_to_treat_as_cstrings =
218
255
function_arguments_to_treat_as_cstrings;
219
256
recursive_initialization = util_make_unique<recursive_initializationt>(
@@ -269,7 +306,7 @@ void function_call_harness_generatort::implt::generate_initialisation_code_for(
269
306
void function_call_harness_generatort::validate_options (
270
307
const goto_modelt &goto_model)
271
308
{
272
- if (p_impl->function == ID_empty )
309
+ if (p_impl->function == ID_empty_string )
273
310
throw invalid_command_line_argument_exceptiont{
274
311
" required parameter entry function not set" ,
275
312
" --" FUNCTION_HARNESS_GENERATOR_FUNCTION_OPT};
@@ -283,8 +320,17 @@ void function_call_harness_generatort::validate_options(
283
320
" --" COMMON_HARNESS_GENERATOR_MAX_ARRAY_SIZE_OPT};
284
321
}
285
322
286
- auto function_to_call = goto_model.symbol_table .lookup_ref (p_impl->function );
287
- auto ftype = to_code_type (function_to_call.type );
323
+ const auto function_to_call_pointer =
324
+ goto_model.symbol_table .lookup (p_impl->function );
325
+ if (function_to_call_pointer == nullptr )
326
+ {
327
+ throw invalid_command_line_argument_exceptiont{
328
+ " entry function `" + id2string (p_impl->function ) +
329
+ " ' does not exist in the symbol table" ,
330
+ " --" FUNCTION_HARNESS_GENERATOR_FUNCTION_OPT};
331
+ }
332
+ const auto &function_to_call = *function_to_call_pointer;
333
+ const auto &ftype = to_code_type (function_to_call.type );
288
334
for (auto const &equal_cluster : p_impl->function_parameters_to_treat_equal )
289
335
{
290
336
for (auto const &pointer_id : equal_cluster)
@@ -325,6 +371,43 @@ void function_call_harness_generatort::validate_options(
325
371
}
326
372
}
327
373
}
374
+
375
+ const namespacet ns{goto_model.symbol_table };
376
+
377
+ // Make sure all function pointers that the user asks are nullable are
378
+ // present in the symbol table.
379
+ for (const auto &nullable :
380
+ p_impl->recursive_initialization_config .potential_null_function_pointers )
381
+ {
382
+ const auto &function_pointer_symbol_pointer =
383
+ goto_model.symbol_table .lookup (nullable);
384
+
385
+ if (function_pointer_symbol_pointer == nullptr )
386
+ {
387
+ throw invalid_command_line_argument_exceptiont{
388
+ " nullable function pointer `" + id2string (nullable) +
389
+ " ' not found in symbol table" ,
390
+ " --" COMMON_HARNESS_GENERATOR_FUNCTION_POINTER_CAN_BE_NULL_OPT};
391
+ }
392
+
393
+ const auto &function_pointer_type =
394
+ ns.follow (function_pointer_symbol_pointer->type );
395
+
396
+ if (!can_cast_type<pointer_typet>(function_pointer_type))
397
+ {
398
+ throw invalid_command_line_argument_exceptiont{
399
+ " `" + id2string (nullable) + " ' is not a pointer" ,
400
+ " --" COMMON_HARNESS_GENERATOR_FUNCTION_POINTER_CAN_BE_NULL_OPT};
401
+ }
402
+
403
+ if (!can_cast_type<code_typet>(
404
+ to_pointer_type (function_pointer_type).subtype ()))
405
+ {
406
+ throw invalid_command_line_argument_exceptiont{
407
+ " `" + id2string (nullable) + " ' is not pointing to a function" ,
408
+ " --" COMMON_HARNESS_GENERATOR_FUNCTION_POINTER_CAN_BE_NULL_OPT};
409
+ }
410
+ }
328
411
}
329
412
330
413
const symbolt &
@@ -469,3 +552,25 @@ void function_call_harness_generatort::implt::call_function(
469
552
470
553
function_body.add (std::move (function_call));
471
554
}
555
+
556
+ std::unordered_set<irep_idt> function_call_harness_generatort::implt::
557
+ map_function_parameters_to_function_argument_names ()
558
+ {
559
+ std::unordered_set<irep_idt> nullables;
560
+ for (const auto &nullable :
561
+ recursive_initialization_config.potential_null_function_pointers )
562
+ {
563
+ const auto &nullable_name = id2string (nullable);
564
+ const auto &function_prefix = id2string (function) + " ::" ;
565
+ if (has_prefix (nullable_name, function_prefix))
566
+ {
567
+ nullables.insert (
568
+ " __goto_harness::" + nullable_name.substr (function_prefix.size ()));
569
+ }
570
+ else
571
+ {
572
+ nullables.insert (nullable_name);
573
+ }
574
+ }
575
+ return nullables;
576
+ }
0 commit comments