@@ -81,6 +81,16 @@ struct function_call_harness_generatort::implt
81
81
void call_function (
82
82
const code_function_callt::argumentst &arguments,
83
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 correspond 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 ();
84
94
};
85
95
86
96
function_call_harness_generatort::function_call_harness_generatort (
@@ -218,6 +228,8 @@ void function_call_harness_generatort::implt::generate(
218
228
recursive_initialization_config.variables_that_hold_array_sizes .insert (
219
229
pair.second );
220
230
}
231
+ recursive_initialization_config.potential_null_function_pointers =
232
+ map_function_parameters_to_function_argument_names ();
221
233
recursive_initialization_config.pointers_to_treat_as_cstrings =
222
234
function_arguments_to_treat_as_cstrings;
223
235
recursive_initialization = util_make_unique<recursive_initializationt>(
@@ -335,6 +347,43 @@ void function_call_harness_generatort::validate_options(
335
347
" --" FUNCTION_HARNESS_GENERATOR_TREAT_POINTERS_EQUAL_OPT};
336
348
}
337
349
}
350
+
351
+ const namespacet ns{goto_model.symbol_table };
352
+
353
+ // Make sure all function pointers that the user asks are nullable are
354
+ // present in the symbol table.
355
+ for (const auto &nullable :
356
+ p_impl->recursive_initialization_config .potential_null_function_pointers )
357
+ {
358
+ const auto &function_pointer_symbol_pointer =
359
+ goto_model.symbol_table .lookup (nullable);
360
+
361
+ if (function_pointer_symbol_pointer == nullptr )
362
+ {
363
+ throw invalid_command_line_argument_exceptiont{
364
+ " nullable function pointer `" + id2string (nullable) +
365
+ " ' not found in symbol table" ,
366
+ " --" COMMON_HARNESS_GENERATOR_FUNCTION_POINTER_CAN_BE_NULL_OPT};
367
+ }
368
+
369
+ const auto &function_pointer_type =
370
+ ns.follow (function_pointer_symbol_pointer->type );
371
+
372
+ if (!can_cast_type<pointer_typet>(function_pointer_type))
373
+ {
374
+ throw invalid_command_line_argument_exceptiont{
375
+ " `" + id2string (nullable) + " ' is not a pointer" ,
376
+ " --" COMMON_HARNESS_GENERATOR_FUNCTION_POINTER_CAN_BE_NULL_OPT};
377
+ }
378
+
379
+ if (!can_cast_type<code_typet>(
380
+ to_pointer_type (function_pointer_type).subtype ()))
381
+ {
382
+ throw invalid_command_line_argument_exceptiont{
383
+ " `" + id2string (nullable) + " ' is not pointing to a function" ,
384
+ " --" COMMON_HARNESS_GENERATOR_FUNCTION_POINTER_CAN_BE_NULL_OPT};
385
+ }
386
+ }
338
387
}
339
388
340
389
const symbolt &
@@ -468,3 +517,25 @@ void function_call_harness_generatort::implt::call_function(
468
517
469
518
function_body.add (std::move (function_call));
470
519
}
520
+
521
+ std::unordered_set<irep_idt> function_call_harness_generatort::implt::
522
+ map_function_parameters_to_function_argument_names ()
523
+ {
524
+ std::unordered_set<irep_idt> nullables;
525
+ for (const auto &nullable :
526
+ recursive_initialization_config.potential_null_function_pointers )
527
+ {
528
+ const auto &nullable_name = id2string (nullable);
529
+ const auto &function_prefix = id2string (function) + " ::" ;
530
+ if (has_prefix (nullable_name, function_prefix))
531
+ {
532
+ nullables.insert (
533
+ " __goto_harness::" + nullable_name.substr (function_prefix.size ()));
534
+ }
535
+ else
536
+ {
537
+ nullables.insert (nullable_name);
538
+ }
539
+ }
540
+ return nullables;
541
+ }
0 commit comments