28
28
29
29
#define JAVA_MAIN_METHOD " main:([Ljava/lang/String;)V"
30
30
31
+ static optionalt<codet> record_return_value (
32
+ const symbolt &function,
33
+ const symbol_table_baset &symbol_table);
34
+
35
+ static code_blockt record_pointer_parameters (
36
+ const symbolt &function,
37
+ const std::vector<exprt> &arguments,
38
+ const symbol_table_baset &symbol_table);
39
+
40
+ static codet record_exception (
41
+ const symbolt &function,
42
+ const symbol_table_baset &symbol_table);
43
+
31
44
static void create_initialize (symbol_table_baset &symbol_table)
32
45
{
33
46
// If __CPROVER_initialize already exists, replace it. It may already exist
@@ -72,22 +85,6 @@ static bool should_init_symbol(const symbolt &sym)
72
85
return is_java_string_literal_id (sym.name );
73
86
}
74
87
75
- // / Get the symbol name of java.lang.Class' initializer method. This method
76
- // / should initialize a Class instance with known properties of the type it
77
- // / represents, such as its name, whether it is abstract, or an enumeration,
78
- // / etc. The method may or may not exist in any particular symbol table; it is
79
- // / up to the caller to check.
80
- // / The method's Java signature is:
81
- // / void cproverInitializeClassLiteral(
82
- // / String name,
83
- // / boolean isAnnotation,
84
- // / boolean isArray,
85
- // / boolean isInterface,
86
- // / boolean isSynthetic,
87
- // / boolean isLocalClass,
88
- // / boolean isMemberClass,
89
- // / boolean isEnum);
90
- // / \return Class initializer method's symbol name.
91
88
irep_idt get_java_class_literal_initializer_signature ()
92
89
{
93
90
static irep_idt signature =
@@ -294,18 +291,8 @@ bool is_java_main(const symbolt &function)
294
291
return named_main && is_static && has_correct_type && public_access;
295
292
}
296
293
297
- // / Extends \p init_code with code that allocates the objects used as test
298
- // / arguments for the function under test (\p function) and
299
- // / non-deterministically initializes them.
300
- // /
301
- // / All the code generated by this function goes to __CPROVER__start, just
302
- // / before the call to the method under test.
303
- // /
304
- // / \returns A std::vector of symbol_exprt, one per parameter of \p function,
305
- // / containing the objects that can be used as arguments for \p function.
306
- exprt::operandst java_build_arguments (
294
+ std::pair<code_blockt, std::vector<exprt>> java_build_arguments (
307
295
const symbolt &function,
308
- code_blockt &init_code,
309
296
symbol_table_baset &symbol_table,
310
297
bool assume_init_pointers_not_null,
311
298
java_object_factory_parameterst object_factory_parameters,
@@ -314,6 +301,7 @@ exprt::operandst java_build_arguments(
314
301
const java_method_typet::parameterst ¶meters =
315
302
to_java_method_type (function.type ).parameters ();
316
303
304
+ code_blockt init_code;
317
305
exprt::operandst main_arguments;
318
306
main_arguments.resize (parameters.size ());
319
307
@@ -444,83 +432,98 @@ exprt::operandst java_build_arguments(
444
432
init_code.add (std::move (input));
445
433
}
446
434
447
- return main_arguments;
435
+ return make_pair (init_code, main_arguments) ;
448
436
}
449
437
450
- void java_record_outputs (
438
+ // / Mark return value, pointer type parameters and the exception as outputs.
439
+ static code_blockt java_record_outputs (
451
440
const symbolt &function,
452
441
const exprt::operandst &main_arguments,
453
- code_blockt &init_code,
454
442
symbol_table_baset &symbol_table)
455
443
{
456
- const java_method_typet::parameterst ¶meters =
457
- to_java_method_type (function.type ).parameters ();
444
+ code_blockt init_code;
458
445
459
- exprt::operandst result;
460
- result.reserve (parameters.size ()+1 );
446
+ if (auto return_value = record_return_value (function, symbol_table))
447
+ {
448
+ init_code.add (std::move (*return_value));
449
+ }
461
450
462
- bool has_return_value =
463
- to_java_method_type (function. type ). return_type () != java_void_type ( );
451
+ init_code. append (
452
+ record_pointer_parameters (function, main_arguments, symbol_table) );
464
453
465
- if (has_return_value)
466
- {
467
- // record return value
468
- codet output (ID_output);
469
- output.operands ().resize (2 );
454
+ init_code.add (record_exception (function, symbol_table));
470
455
471
- const symbolt &return_symbol=
472
- *symbol_table. lookup (JAVA_ENTRY_POINT_RETURN_SYMBOL);
456
+ return init_code;
457
+ }
473
458
474
- output.op0 ()=
475
- address_of_exprt (
476
- index_exprt (
477
- string_constantt (return_symbol.base_name ),
478
- from_integer (0 , index_type ())));
479
- output.op1 ()=return_symbol.symbol_expr ();
480
- output.add_source_location ()=function.location ;
459
+ static optionalt<codet> record_return_value (
460
+ const symbolt &function,
461
+ const symbol_table_baset &symbol_table)
462
+ {
463
+ if (to_java_method_type (function.type ).return_type () == java_void_type ())
464
+ return {};
481
465
482
- init_code. add ( std::move (output));
483
- }
466
+ const symbolt &return_symbol =
467
+ *symbol_table. lookup (JAVA_ENTRY_POINT_RETURN_SYMBOL);
484
468
485
- for (std::size_t param_number=0 ;
486
- param_number<parameters.size ();
469
+ codet output (ID_output);
470
+ output.operands ().resize (2 );
471
+ output.op0 () = address_of_exprt (index_exprt (
472
+ string_constantt (return_symbol.base_name ), from_integer (0 , index_type ())));
473
+ output.op1 () = return_symbol.symbol_expr ();
474
+ output.add_source_location () = function.location ;
475
+ return output;
476
+ }
477
+
478
+ static code_blockt record_pointer_parameters (
479
+ const symbolt &function,
480
+ const std::vector<exprt> &arguments,
481
+ const symbol_table_baset &symbol_table)
482
+ {
483
+ const java_method_typet::parameterst ¶meters =
484
+ to_java_method_type (function.type ).parameters ();
485
+
486
+ code_blockt init_code;
487
+
488
+ for (std::size_t param_number = 0 ; param_number < parameters.size ();
487
489
param_number++)
488
490
{
489
- const symbolt &p_symbol=
491
+ const symbolt &p_symbol =
490
492
*symbol_table.lookup (parameters[param_number].get_identifier ());
491
493
492
- if (p_symbol.type .id ()==ID_pointer)
493
- {
494
- // record as an output
495
- codet output (ID_output);
496
- output.operands ().resize (2 );
497
- output.op0 ()=
498
- address_of_exprt (
499
- index_exprt (
500
- string_constantt (p_symbol.base_name ),
501
- from_integer (0 , index_type ())));
502
- output.op1 ()=main_arguments[param_number];
503
- output.add_source_location ()=function.location ;
504
-
505
- init_code.add (std::move (output));
506
- }
494
+ if (!can_cast_type<pointer_typet>(p_symbol.type ))
495
+ continue ;
496
+
497
+ codet output (ID_output);
498
+ output.operands ().resize (2 );
499
+ output.op0 () = address_of_exprt (index_exprt (
500
+ string_constantt (p_symbol.base_name ), from_integer (0 , index_type ())));
501
+ output.op1 () = arguments[param_number];
502
+ output.add_source_location () = function.location ;
503
+
504
+ init_code.add (std::move (output));
507
505
}
506
+ return init_code;
507
+ }
508
508
509
+ static codet record_exception (
510
+ const symbolt &function,
511
+ const symbol_table_baset &symbol_table)
512
+ {
509
513
// record exceptional return variable as output
510
514
codet output (ID_output);
511
515
output.operands ().resize (2 );
512
516
513
517
// retrieve the exception variable
514
- const symbolt exc_symbol=*symbol_table. lookup (
515
- JAVA_ENTRY_POINT_EXCEPTION_SYMBOL);
518
+ const symbolt & exc_symbol =
519
+ symbol_table. lookup_ref ( JAVA_ENTRY_POINT_EXCEPTION_SYMBOL);
516
520
517
521
output.op0 ()=address_of_exprt (
518
522
index_exprt (string_constantt (exc_symbol.base_name ),
519
523
from_integer (0 , index_type ())));
520
524
output.op1 ()=exc_symbol.symbol_expr ();
521
525
output.add_source_location ()=function.location ;
522
-
523
- init_code.add (std::move (output));
526
+ return output;
524
527
}
525
528
526
529
main_function_resultt get_main_symbol (
@@ -580,40 +583,6 @@ main_function_resultt get_main_symbol(
580
583
}
581
584
}
582
585
583
- // / Given the \p symbol_table and the \p main_class to test, this function
584
- // / generates a new function __CPROVER__start that calls the method under tests.
585
- // /
586
- // / If __CPROVER__start is already in the `symbol_table`, it silently returns.
587
- // / Otherwise it finds the method under test using `get_main_symbol` and
588
- // / constructs a body for __CPROVER__start which does as follows:
589
- // /
590
- // / 1. Allocates and initializes the parameters of the method under test.
591
- // / 2. Call it and save its return variable in the variable 'return'.
592
- // / 3. Declare variable 'return' as an output variable (codet with id
593
- // / ID_output), together with other objects possibly altered by the execution
594
- // / the method under test (in `java_record_outputs`)
595
- // /
596
- // / When \p assume_init_pointers_not_null is false, the generated parameter
597
- // / initialization code will non-deterministically set input parameters to
598
- // / either null or a stack-allocated object. Observe that the null/non-null
599
- // / setting only applies to the parameter itself, and is not propagated to other
600
- // / pointers that it might be necessary to initialize in the object tree rooted
601
- // / at the parameter.
602
- // / Parameter \p max_nondet_array_length provides the maximum length for an
603
- // / array used as part of the input to the method under test, and
604
- // / \p max_nondet_tree_depth defines the maximum depth of the object tree
605
- // / created for such inputs. This maximum depth is used **in conjunction** with
606
- // / the so-called "recursive type set" (see field `recursive_set` in class
607
- // / java_object_factoryt) to bound the depth of the object tree for the
608
- // / parameter. Only when
609
- // / - the depth of the tree is >= max_nondet_tree_depth **AND**
610
- // / - the type of the object under initialization is already found in the
611
- // / recursive set
612
- // / then that object is not initalized and the reference pointing to it is
613
- // / (deterministically) set to null. This is a source of underapproximation in
614
- // / our approach to test generation, and should perhaps be fixed in the future.
615
- // /
616
- // / \return true if error occurred on entry point search
617
586
bool java_entry_point (
618
587
symbol_table_baset &symbol_table,
619
588
const irep_idt &main_class,
@@ -622,7 +591,8 @@ bool java_entry_point(
622
591
bool assert_uncaught_exceptions,
623
592
const java_object_factory_parameterst &object_factory_parameters,
624
593
const select_pointer_typet &pointer_type_selector,
625
- bool string_refinement_enabled)
594
+ bool string_refinement_enabled,
595
+ const build_argumentst &build_arguments)
626
596
{
627
597
// check if the entry point is already there
628
598
if (symbol_table.symbols .find (goto_functionst::entry_point ())!=
@@ -653,31 +623,20 @@ bool java_entry_point(
653
623
symbol,
654
624
symbol_table,
655
625
message_handler,
656
- assume_init_pointers_not_null,
657
626
assert_uncaught_exceptions,
658
627
object_factory_parameters,
659
- pointer_type_selector);
628
+ pointer_type_selector,
629
+ build_arguments);
660
630
}
661
631
662
- // / Generate a _start function for a specific function. See
663
- // / java_entry_point for more details.
664
- // / \param symbol: The symbol representing the function to call
665
- // / \param symbol_table: Global symbol table
666
- // / \param message_handler: Where to write output to
667
- // / \param assume_init_pointers_not_null: When creating pointers, assume they
668
- // / always take a non-null value.
669
- // / \param assert_uncaught_exceptions: Add an uncaught-exception check
670
- // / \param object_factory_parameters: Parameters for creation of arguments
671
- // / \param pointer_type_selector: Logic for substituting types of pointers
672
- // / \return true if error occurred on entry point search, false otherwise
673
632
bool generate_java_start_function (
674
633
const symbolt &symbol,
675
634
symbol_table_baset &symbol_table,
676
635
message_handlert &message_handler,
677
- bool assume_init_pointers_not_null,
678
636
bool assert_uncaught_exceptions,
679
637
const java_object_factory_parameterst &object_factory_parameters,
680
- const select_pointer_typet &pointer_type_selector)
638
+ const select_pointer_typet &pointer_type_selector,
639
+ const build_argumentst &build_arguments)
681
640
{
682
641
messaget message (message_handler);
683
642
code_blockt init_code;
@@ -744,15 +703,10 @@ bool generate_java_start_function(
744
703
745
704
// create code that allocates the objects used as test arguments and
746
705
// non-deterministically initializes them
747
- exprt::operandst main_arguments=
748
- java_build_arguments (
749
- symbol,
750
- init_code,
751
- symbol_table,
752
- assume_init_pointers_not_null,
753
- object_factory_parameters,
754
- pointer_type_selector);
755
- call_main.arguments ()=main_arguments;
706
+ const std::pair<code_blockt, std::vector<exprt>> main_arguments =
707
+ build_arguments (symbol, symbol_table);
708
+ init_code.append (main_arguments.first );
709
+ call_main.arguments () = main_arguments.second ;
756
710
757
711
// Create target labels for the toplevel exception handler:
758
712
code_labelt toplevel_catch (" toplevel_catch" , code_skipt ());
@@ -791,8 +745,9 @@ bool generate_java_start_function(
791
745
// Converge normal and exceptional return:
792
746
init_code.add (std::move (after_catch));
793
747
794
- // declare certain (which?) variables as test outputs
795
- java_record_outputs (symbol, main_arguments, init_code, symbol_table);
748
+ // Mark return value, pointer type parameters and the exception as outputs.
749
+ init_code.append (
750
+ java_record_outputs (symbol, main_arguments.second , symbol_table));
796
751
797
752
// add uncaught-exception check if requested
798
753
if (assert_uncaught_exceptions)
0 commit comments