@@ -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>
@@ -48,6 +49,9 @@ struct function_call_harness_generatort::implt
48
49
std::set<irep_idt> function_parameters_to_treat_as_arrays;
49
50
std::set<irep_idt> function_arguments_to_treat_as_arrays;
50
51
52
+ std::set<irep_idt> function_parameters_to_treat_equal;
53
+ std::set<irep_idt> function_arguments_to_treat_equal;
54
+
51
55
std::set<irep_idt> function_parameters_to_treat_as_cstrings;
52
56
std::set<irep_idt> function_arguments_to_treat_as_cstrings;
53
57
@@ -69,14 +73,24 @@ struct function_call_harness_generatort::implt
69
73
void ensure_harness_does_not_already_exist ();
70
74
// / Update the goto-model with the new harness function.
71
75
void add_harness_function_to_goto_model (code_blockt function_body);
72
- // / 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
73
77
// / and return them
74
78
code_function_callt::argumentst declare_arguments (code_blockt &function_body);
75
- // / write initialisation code for each of the arguments into function_body,
79
+ // / Write initialisation code for each of the arguments into function_body,
76
80
// / then insert a call to the entry function with the arguments
77
81
void call_function (
78
82
const code_function_callt::argumentst &arguments,
79
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 ();
80
94
};
81
95
82
96
function_call_harness_generatort::function_call_harness_generatort (
@@ -112,6 +126,16 @@ void function_call_harness_generatort::handle_option(
112
126
p_impl->function_parameters_to_treat_as_arrays .insert (
113
127
values.begin (), values.end ());
114
128
}
129
+ else if (option == FUNCTION_HARNESS_GENERATOR_TREAT_POINTERS_EQUAL_OPT)
130
+ {
131
+ for (auto const &value : values)
132
+ {
133
+ for (auto const ¶m_id : split_string (value, ' ,' ))
134
+ {
135
+ p_impl->function_parameters_to_treat_equal .insert (param_id);
136
+ }
137
+ }
138
+ }
115
139
else if (option == FUNCTION_HARNESS_GENERATOR_ASSOCIATED_ARRAY_SIZE_OPT)
116
140
{
117
141
for (auto const &array_size_pair : values)
@@ -183,13 +207,17 @@ void function_call_harness_generatort::implt::generate(
183
207
recursive_initialization_config.mode = function_to_call.mode ;
184
208
recursive_initialization_config.pointers_to_treat_as_arrays =
185
209
function_arguments_to_treat_as_arrays;
210
+ recursive_initialization_config.pointers_to_treat_equal =
211
+ function_arguments_to_treat_equal;
186
212
recursive_initialization_config.array_name_to_associated_array_size_variable =
187
213
function_argument_to_associated_array_size;
188
214
for (const auto &pair : function_argument_to_associated_array_size)
189
215
{
190
216
recursive_initialization_config.variables_that_hold_array_sizes .insert (
191
217
pair.second );
192
218
}
219
+ recursive_initialization_config.potential_null_function_pointers =
220
+ map_function_parameters_to_function_argument_names ();
193
221
recursive_initialization_config.pointers_to_treat_as_cstrings =
194
222
function_arguments_to_treat_as_cstrings;
195
223
recursive_initialization = util_make_unique<recursive_initializationt>(
@@ -238,14 +266,14 @@ void function_call_harness_generatort::implt::generate_initialisation_code_for(
238
266
{
239
267
recursive_initialization->initialize (
240
268
lhs, from_integer (0 , signed_int_type ()), block);
241
- if (lhs. type (). id () == ID_pointer )
269
+ if (recursive_initialization-> needs_freeing (lhs) )
242
270
global_pointers.insert (to_symbol_expr (lhs));
243
271
}
244
272
245
273
void function_call_harness_generatort::validate_options (
246
274
const goto_modelt &goto_model)
247
275
{
248
- if (p_impl->function == ID_empty )
276
+ if (p_impl->function == ID_empty_string )
249
277
throw invalid_command_line_argument_exceptiont{
250
278
" required parameter entry function not set" ,
251
279
" --" FUNCTION_HARNESS_GENERATOR_FUNCTION_OPT};
@@ -258,6 +286,92 @@ void function_call_harness_generatort::validate_options(
258
286
" --" COMMON_HARNESS_GENERATOR_MIN_ARRAY_SIZE_OPT
259
287
" --" COMMON_HARNESS_GENERATOR_MAX_ARRAY_SIZE_OPT};
260
288
}
289
+
290
+ const auto function_to_call_pointer =
291
+ goto_model.symbol_table .lookup (p_impl->function );
292
+ if (function_to_call_pointer == nullptr )
293
+ {
294
+ throw invalid_command_line_argument_exceptiont{
295
+ " entry function `" + id2string (p_impl->function ) +
296
+ " ' does not exist in the symbol table" ,
297
+ " --" FUNCTION_HARNESS_GENERATOR_FUNCTION_OPT};
298
+ }
299
+ const auto &function_to_call = *function_to_call_pointer;
300
+ const auto &ftype = to_code_type (function_to_call.type );
301
+ for (auto const &pointer_id : p_impl->function_parameters_to_treat_equal )
302
+ {
303
+ std::string decorated_pointer_id =
304
+ id2string (p_impl->function ) + " ::" + id2string (pointer_id);
305
+ bool is_a_param = false ;
306
+ typet common_type = empty_typet{};
307
+ for (auto const &formal_param : ftype.parameters ())
308
+ {
309
+ if (formal_param.get_identifier () == decorated_pointer_id)
310
+ {
311
+ is_a_param = true ;
312
+ if (formal_param.type ().id () != ID_pointer)
313
+ {
314
+ throw invalid_command_line_argument_exceptiont{
315
+ id2string (pointer_id) + " is not a pointer parameter" ,
316
+ " --" FUNCTION_HARNESS_GENERATOR_TREAT_POINTERS_EQUAL_OPT};
317
+ }
318
+ if (common_type.id () != ID_empty)
319
+ {
320
+ if (common_type != formal_param.type ())
321
+ {
322
+ throw invalid_command_line_argument_exceptiont{
323
+ " pointer arguments of conflicting type" ,
324
+ " --" FUNCTION_HARNESS_GENERATOR_TREAT_POINTERS_EQUAL_OPT};
325
+ }
326
+ }
327
+ else
328
+ common_type = formal_param.type ();
329
+ }
330
+ }
331
+ if (!is_a_param)
332
+ {
333
+ throw invalid_command_line_argument_exceptiont{
334
+ id2string (pointer_id) + " is not a parameter" ,
335
+ " --" FUNCTION_HARNESS_GENERATOR_TREAT_POINTERS_EQUAL_OPT};
336
+ }
337
+ }
338
+
339
+ const namespacet ns{goto_model.symbol_table };
340
+
341
+ // Make sure all function pointers that the user asks are nullable are
342
+ // present in the symbol table.
343
+ for (const auto &nullable :
344
+ p_impl->recursive_initialization_config .potential_null_function_pointers )
345
+ {
346
+ const auto &function_pointer_symbol_pointer =
347
+ goto_model.symbol_table .lookup (nullable);
348
+
349
+ if (function_pointer_symbol_pointer == nullptr )
350
+ {
351
+ throw invalid_command_line_argument_exceptiont{
352
+ " nullable function pointer `" + id2string (nullable) +
353
+ " ' not found in symbol table" ,
354
+ " --" COMMON_HARNESS_GENERATOR_FUNCTION_POINTER_CAN_BE_NULL_OPT};
355
+ }
356
+
357
+ const auto &function_pointer_type =
358
+ ns.follow (function_pointer_symbol_pointer->type );
359
+
360
+ if (!can_cast_type<pointer_typet>(function_pointer_type))
361
+ {
362
+ throw invalid_command_line_argument_exceptiont{
363
+ " `" + id2string (nullable) + " ' is not a pointer" ,
364
+ " --" COMMON_HARNESS_GENERATOR_FUNCTION_POINTER_CAN_BE_NULL_OPT};
365
+ }
366
+
367
+ if (!can_cast_type<code_typet>(
368
+ to_pointer_type (function_pointer_type).subtype ()))
369
+ {
370
+ throw invalid_command_line_argument_exceptiont{
371
+ " `" + id2string (nullable) + " ' is not pointing to a function" ,
372
+ " --" COMMON_HARNESS_GENERATOR_FUNCTION_POINTER_CAN_BE_NULL_OPT};
373
+ }
374
+ }
261
375
}
262
376
263
377
const symbolt &
@@ -348,6 +462,11 @@ function_call_harness_generatort::implt::declare_arguments(
348
462
function_arguments_to_treat_as_cstrings.insert (argument_name);
349
463
}
350
464
465
+ if (function_parameters_to_treat_equal.count (parameter_name) != 0 )
466
+ {
467
+ function_arguments_to_treat_equal.insert (argument_name);
468
+ }
469
+
351
470
auto it = function_parameter_to_associated_array_size.find (parameter_name);
352
471
if (it != function_parameter_to_associated_array_size.end ())
353
472
{
@@ -377,7 +496,7 @@ void function_call_harness_generatort::implt::call_function(
377
496
for (auto const &argument : arguments)
378
497
{
379
498
generate_initialisation_code_for (function_body, argument);
380
- if (argument. type (). id () == ID_pointer )
499
+ if (recursive_initialization-> needs_freeing (argument) )
381
500
global_pointers.insert (to_symbol_expr (argument));
382
501
}
383
502
code_function_callt function_call{function_to_call.symbol_expr (),
@@ -386,3 +505,25 @@ void function_call_harness_generatort::implt::call_function(
386
505
387
506
function_body.add (std::move (function_call));
388
507
}
508
+
509
+ std::unordered_set<irep_idt> function_call_harness_generatort::implt::
510
+ map_function_parameters_to_function_argument_names ()
511
+ {
512
+ std::unordered_set<irep_idt> nullables;
513
+ for (const auto &nullable :
514
+ recursive_initialization_config.potential_null_function_pointers )
515
+ {
516
+ const auto &nullable_name = id2string (nullable);
517
+ const auto &function_prefix = id2string (function) + " ::" ;
518
+ if (has_prefix (nullable_name, function_prefix))
519
+ {
520
+ nullables.insert (
521
+ " __goto_harness::" + nullable_name.substr (function_prefix.size ()));
522
+ }
523
+ else
524
+ {
525
+ nullables.insert (nullable_name);
526
+ }
527
+ }
528
+ return nullables;
529
+ }
0 commit comments