@@ -72,7 +72,7 @@ require_goto_statements::find_struct_component_assignments(
72
72
const irep_idt &component_name,
73
73
const symbol_tablet &symbol_table)
74
74
{
75
- pointer_assignment_locationt locations;
75
+ pointer_assignment_locationt locations{} ;
76
76
77
77
for (const auto &assignment : statements)
78
78
{
@@ -106,8 +106,8 @@ require_goto_statements::find_struct_component_assignments(
106
106
ode.build (superclass_expr, ns);
107
107
if (
108
108
superclass_expr.get_component_name () == supercomponent_name &&
109
- to_symbol_expr (ode.root_object ()).get_identifier () ==
110
- structure_name)
109
+ to_symbol_expr (to_dereference_expr ( ode.root_object ()).pointer ())
110
+ . get_identifier () == structure_name)
111
111
{
112
112
if (
113
113
code_assign.rhs () ==
@@ -133,10 +133,9 @@ require_goto_statements::find_struct_component_assignments(
133
133
const namespacet ns (symbol_table);
134
134
ode.build (member_expr, ns);
135
135
if (
136
- ode.root_object ().id () == ID_symbol &&
137
- to_symbol_expr (ode.root_object ()).get_identifier () ==
138
- structure_name &&
139
- member_expr.get_component_name () == component_name)
136
+ member_expr.get_component_name () == component_name &&
137
+ to_symbol_expr (to_dereference_expr (ode.root_object ()).pointer ())
138
+ .get_identifier () == structure_name)
140
139
{
141
140
if (
142
141
code_assign.rhs () ==
@@ -295,6 +294,73 @@ const code_declt &require_goto_statements::require_declaration_of_name(
295
294
throw no_decl_found_exceptiont (variable_name.c_str ());
296
295
}
297
296
297
+ // / Get the unique non-null expression assigned to a symbol. The symbol may have
298
+ // / many null assignments, but only one non-null assignment.
299
+ // / \param entry_point_instructions: A vector of instructions
300
+ // / \param symbol_identifier: The identifier of the symbol we are considering
301
+ // / \return The unique non-null expression assigned to the symbol
302
+ const exprt &get_unique_non_null_expression_assigned_to_symbol (
303
+ const std::vector<codet> &entry_point_instructions,
304
+ const irep_idt &symbol_identifier)
305
+ {
306
+ const auto &assignments = require_goto_statements::find_pointer_assignments (
307
+ symbol_identifier, entry_point_instructions)
308
+ .non_null_assignments ;
309
+ REQUIRE (assignments.size () == 1 );
310
+ return assignments[0 ].rhs ();
311
+ }
312
+
313
+ // / Get the unique symbol assigned to a symbol, if one exists. There must be
314
+ // / a unique non-null assignment to the symbol, and it is either another symbol,
315
+ // / in which case we return that symbol expression, or something else, which
316
+ // / case we return a null pointer.
317
+ // / \param entry_point_instructions: A vector of instructions
318
+ // / \param symbol_identifier: The identifier of the symbol
319
+ // / \return The unique symbol assigned to \p input_symbol_identifier, or a null
320
+ // / pointer if no symbols are assigned to it
321
+ const symbol_exprt *try_get_unique_symbol_assigned_to_symbol (
322
+ const std::vector<codet> &entry_point_instructions,
323
+ const irep_idt &symbol_identifier)
324
+ {
325
+ const auto &expr = get_unique_non_null_expression_assigned_to_symbol (
326
+ entry_point_instructions, symbol_identifier);
327
+
328
+ return expr_try_dynamic_cast<symbol_exprt>(skip_typecast (expr));
329
+ }
330
+
331
+ // / Follow the chain of non-null assignments until we find a symbol that
332
+ // / hasn't ever had another symbol assigned to it. For example, if this code is
333
+ // / ```
334
+ // / a = 5 + g(7)
335
+ // / b = a
336
+ // / c = b
337
+ // / ```
338
+ // / then given input c we return a.
339
+ // / \param entry_point_instructions: A vector of instructions
340
+ // / \param input_symbol_identifier: The identifier of the symbol we are
341
+ // / currently considering
342
+ // / \return The identifier of the symbol which is (possibly indirectly) assigned
343
+ // / to \p input_symbol_identifier and which does not have any symbol assigned
344
+ // / to it
345
+ static const irep_idt &
346
+ get_ultimate_source_symbol (
347
+ const std::vector<codet> &entry_point_instructions,
348
+ const irep_idt &input_symbol_identifier)
349
+ {
350
+ const symbol_exprt *symbol_assigned_to_input_symbol =
351
+ try_get_unique_symbol_assigned_to_symbol (
352
+ entry_point_instructions, input_symbol_identifier);
353
+
354
+ if (symbol_assigned_to_input_symbol)
355
+ {
356
+ return get_ultimate_source_symbol (
357
+ entry_point_instructions,
358
+ symbol_assigned_to_input_symbol->get_identifier ());
359
+ }
360
+
361
+ return input_symbol_identifier;
362
+ }
363
+
298
364
// / Checks that the component of the structure (possibly inherited from
299
365
// / the superclass) is assigned an object of the given type.
300
366
// / \param structure_name: The name the variable
@@ -305,7 +371,9 @@ const code_declt &require_goto_statements::require_declaration_of_name(
305
371
// / there is a typecast)
306
372
// / \param entry_point_instructions: The statements to look through
307
373
// / \param symbol_table: A symbol table to enable type lookups
308
- // / \return The identifier of the variable assigned to the field
374
+ // / \return The identifier of the ultimate source symbol assigned to the field,
375
+ // / which will be used for future calls to
376
+ // / `require_struct_component_assignment`.
309
377
const irep_idt &require_goto_statements::require_struct_component_assignment (
310
378
const irep_idt &structure_name,
311
379
const optionalt<irep_idt> &superclass_name,
@@ -331,48 +399,31 @@ const irep_idt &require_goto_statements::require_struct_component_assignment(
331
399
<< structure_name);
332
400
REQUIRE (component_assignments.non_null_assignments .size () == 1 );
333
401
334
- // We are expecting that the resulting statement can be of the form:
335
- // 1. structure_name.(@superclass_name if given).component =
336
- // (optional type cast *) tmp_object_factory$1;
337
- // followed by a direct assignment like this:
338
- // tmp_object_factory$1 = &tmp_object_factory$2;
339
- // 2. structure_name.component = (optional cast *)&tmp_object_factory$1
340
- exprt component_assignment_rhs_expr =
341
- skip_typecast (component_assignments.non_null_assignments [0 ].rhs ());
342
-
343
- // If the rhs is not an address of must be in case 1
344
- if (!can_cast_expr<address_of_exprt>(component_assignment_rhs_expr))
345
- {
346
- const auto &component_reference_tmp_name =
347
- to_symbol_expr (component_assignment_rhs_expr).get_identifier ();
348
- const auto &component_reference_assignments =
349
- require_goto_statements::find_pointer_assignments (
350
- component_reference_tmp_name, entry_point_instructions)
351
- .non_null_assignments ;
352
- REQUIRE (component_reference_assignments.size () == 1 );
353
- component_assignment_rhs_expr =
354
- skip_typecast (component_reference_assignments[0 ].rhs ());
355
- }
402
+ // We are expecting the non-null assignment to be of the form:
403
+ // malloc_site->(@superclass_name if given.)field =
404
+ // (possible typecast) malloc_site$0;
405
+ const symbol_exprt *rhs_symbol_expr = expr_try_dynamic_cast<symbol_exprt>(
406
+ skip_typecast (component_assignments.non_null_assignments [0 ].rhs ()));
407
+ REQUIRE (rhs_symbol_expr);
356
408
357
- // The rhs assigns an address of a variable, get its name
358
- const auto &component_reference_assignment_rhs =
359
- to_address_of_expr (component_assignment_rhs_expr);
360
- const auto &component_tmp_name =
361
- to_symbol_expr (component_reference_assignment_rhs.op ()).get_identifier ();
409
+ const irep_idt &symbol_identifier = get_ultimate_source_symbol (
410
+ entry_point_instructions, rhs_symbol_expr->get_identifier ());
362
411
363
412
// After we have found the declaration of the final assignment's
364
413
// right hand side, then we want to identify that the type
365
414
// is the one we expect, e.g.:
366
- // struct java.lang.Integer tmp_object_factory$2 ;
415
+ // struct java.lang.Integer *malloc_site$0 ;
367
416
const auto &component_declaration =
368
417
require_goto_statements::require_declaration_of_name (
369
- component_tmp_name, entry_point_instructions);
370
- REQUIRE (component_declaration.symbol ().type ().id () == ID_struct_tag);
418
+ symbol_identifier, entry_point_instructions);
419
+ const typet &component_type =
420
+ to_pointer_type (component_declaration.symbol ().type ()).subtype ();
421
+ REQUIRE (component_type.id () == ID_struct_tag);
371
422
const auto &component_struct =
372
- ns.follow_tag (to_struct_tag_type (component_declaration. symbol (). type () ));
423
+ ns.follow_tag (to_struct_tag_type (component_type ));
373
424
REQUIRE (component_struct.get (ID_name) == component_type_name);
374
425
375
- return component_tmp_name ;
426
+ return symbol_identifier ;
376
427
}
377
428
378
429
// / Checks that the array component of the structure (possibly inherited from
@@ -462,26 +513,24 @@ require_goto_statements::require_entry_point_argument_assignment(
462
513
{
463
514
// Trace the creation of the object that is being supplied as the input
464
515
// argument to the function under test
465
- const pointer_assignment_locationt & argument_assignments =
516
+ const pointer_assignment_locationt argument_assignments =
466
517
find_pointer_assignments (
467
- id2string (goto_functionst::entry_point ()) + " :: " +
468
- id2string (argument_name),
518
+ id2string (goto_functionst::entry_point ()) +
519
+ " :: " + id2string (argument_name),
469
520
entry_point_statements);
470
521
471
522
// There should be at most one assignment to it
472
523
REQUIRE (argument_assignments.non_null_assignments .size () == 1 );
473
524
474
525
// The following finds the name of the tmp object that gets assigned
475
526
// to the input argument. There must be one such assignment only,
476
- // and usually looks like this:
477
- // argument_name = & tmp_object_factory$1;
527
+ // and it usually looks like this:
528
+ // argument_name = tmp_object_factory$1;
478
529
const auto &argument_assignment =
479
530
argument_assignments.non_null_assignments [0 ];
480
- const auto &argument_tmp_name =
481
- to_symbol_expr (
482
- to_address_of_expr (skip_typecast (argument_assignment.rhs ())).object ())
483
- .get_identifier ();
484
- return argument_tmp_name;
531
+ const symbol_exprt &argument_symbol =
532
+ to_symbol_expr (skip_typecast (argument_assignment.rhs ()));
533
+ return argument_symbol.get_identifier ();
485
534
}
486
535
487
536
// / Verify that a collection of statements contains a function call to a
@@ -512,6 +561,6 @@ std::vector<code_function_callt> require_goto_statements::find_function_calls(
512
561
}
513
562
}
514
563
}
515
- }
564
+ }
516
565
return function_calls;
517
566
}
0 commit comments