@@ -11,13 +11,15 @@ Author: Daniel Kroening, kroening@kroening.com
11
11
#include < util/expr_initializer.h>
12
12
#include < util/fresh_symbol.h>
13
13
#include < util/nondet_bool.h>
14
+ #include < util/nondet.h>
14
15
#include < util/pointer_offset_size.h>
15
16
16
17
#include < goto-programs/class_identifier.h>
17
18
#include < goto-programs/goto_functions.h>
18
19
19
20
#include " generic_parameter_specialization_map_keys.h"
20
21
#include " java_root_class.h"
22
+ #include " java_string_literals.h"
21
23
22
24
class java_object_factoryt
23
25
{
@@ -526,9 +528,11 @@ static mp_integer max_value(const typet &type)
526
528
UNREACHABLE;
527
529
}
528
530
529
- // / Check if a structure is a nondeterministic String structure, and if it is
530
- // / initialize its length and data fields.
531
- // / \param struct_expr [out]: struct that we may initialize
531
+ // / Initialise length and data fields for a nondeterministic String structure.
532
+ // /
533
+ // / If the structure is not a nondeterministic structure, the call results in
534
+ // / a precondition violation.
535
+ // / \param struct_expr [out]: struct that we initialize
532
536
// / \param code: block to add pre-requisite declarations (e.g. to allocate a
533
537
// / data array)
534
538
// / \param min_nondet_string_length: minimum length of strings to initialize
@@ -538,9 +542,6 @@ static mp_integer max_value(const typet &type)
538
542
// / \param symbol_table: the symbol table
539
543
// / \param printable: if true, the nondet string must consist of printable
540
544
// / characters only
541
- // / \return true if struct_expr's length and data fields have been set up,
542
- // / false if we took no action because struct_expr wasn't a CharSequence
543
- // / or didn't have the necessary fields.
544
545
// /
545
546
// / The code produced is of the form:
546
547
// / ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -564,7 +565,7 @@ static mp_integer max_value(const typet &type)
564
565
// / ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
565
566
// / Unit tests in `unit/java_bytecode/java_object_factory/` ensure
566
567
// / it is the case.
567
- bool initialize_nondet_string_fields (
568
+ void initialize_nondet_string_fields (
568
569
struct_exprt &struct_expr,
569
570
code_blockt &code,
570
571
const std::size_t &min_nondet_string_length,
@@ -574,11 +575,9 @@ bool initialize_nondet_string_fields(
574
575
symbol_table_baset &symbol_table,
575
576
bool printable)
576
577
{
577
- if (!java_string_library_preprocesst::implements_java_char_sequence (
578
- struct_expr.type ()))
579
- {
580
- return false ;
581
- }
578
+ PRECONDITION (
579
+ java_string_library_preprocesst
580
+ ::implements_java_char_sequence (struct_expr.type()));
582
581
583
582
namespacet ns (symbol_table);
584
583
@@ -589,8 +588,8 @@ bool initialize_nondet_string_fields(
589
588
// (typically when string refinement is not activated), `struct_type`
590
589
// just contains the standard Object fields (or may have some other model
591
590
// entirely), and in particular has no length and data fields.
592
- if (!struct_type. has_component ( " length " ) || !struct_type. has_component ( " data " ))
593
- return false ;
591
+ PRECONDITION (
592
+ struct_type. has_component ( " length " ) && struct_type. has_component ( " data " )) ;
594
593
595
594
// We allow type StringBuffer and StringBuilder to be initialized
596
595
// in the same way has String, because they have the same structure and
@@ -657,8 +656,6 @@ bool initialize_nondet_string_fields(
657
656
add_character_set_constraint (
658
657
array_pointer, length_expr, " -~" , symbol_table, loc, code);
659
658
}
660
-
661
- return true ;
662
659
}
663
660
664
661
// / Initializes a pointer \p expr of type \p pointer_type to a primitive-typed
@@ -943,6 +940,33 @@ symbol_exprt java_object_factoryt::gen_nondet_subtype_pointer_init(
943
940
return new_symbol.symbol_expr ();
944
941
}
945
942
943
+ // / Creates an alternate_casest vector in which each item contains an
944
+ // / assignment of a string from \p string_input_values (or more precisely the
945
+ // / literal symbol corresponding to the string) to \p expr.
946
+ // / \param expr:
947
+ // / Struct-typed lvalue expression to which we want to assign the strings.
948
+ // / \param string_input_values:
949
+ // / Strings to assign.
950
+ // / \param symbol_table:
951
+ // / The symbol table in which we'll lool up literal symbol
952
+ // / \return A vector that can be passed to generate_nondet_switch
953
+ alternate_casest get_string_input_values_code (
954
+ const exprt &expr,
955
+ const std::list<std::string> &string_input_values,
956
+ symbol_table_baset &symbol_table)
957
+ {
958
+ alternate_casest cases;
959
+ for (const auto &val : string_input_values)
960
+ {
961
+ exprt name_literal (ID_java_string_literal);
962
+ name_literal.set (ID_value, val);
963
+ const symbol_exprt s =
964
+ get_or_create_string_literal_symbol (name_literal, symbol_table, true );
965
+ cases.push_back (code_assignt (expr, s));
966
+ }
967
+ return cases;
968
+ }
969
+
946
970
// / Initializes an object tree rooted at `expr`, allocating child objects as
947
971
// / necessary and nondet-initializes their members, or if MUST_UPDATE_IN_PLACE
948
972
// / is set, re-initializes already-allocated objects.
@@ -1009,31 +1033,67 @@ void java_object_factoryt::gen_nondet_struct_init(
1009
1033
{
1010
1034
class_identifier = struct_tag;
1011
1035
1012
- // Add an initial all-zero write. Most of the fields of this will be
1013
- // overwritten, but it helps to have a whole-structure write that analysis
1014
- // passes can easily recognise leaves no uninitialised state behind.
1015
-
1016
- // This code mirrors the `remove_java_new` pass:
1017
- auto initial_object = zero_initializer (struct_type, source_locationt (), ns);
1018
- CHECK_RETURN (initial_object.has_value ());
1019
- irep_idt qualified_clsid = " java::" + id2string (class_identifier);
1020
- set_class_identifier (
1021
- to_struct_expr (*initial_object), ns, struct_tag_typet (qualified_clsid));
1022
-
1023
- // If the initialised type is a special-cased String type (one with length
1024
- // and data fields introduced by string-library preprocessing), initialise
1025
- // those fields with nondet values:
1026
- skip_special_string_fields = initialize_nondet_string_fields (
1027
- to_struct_expr (*initial_object),
1028
- assignments,
1029
- object_factory_parameters.min_nondet_string_length ,
1030
- object_factory_parameters.max_nondet_string_length ,
1031
- loc,
1032
- object_factory_parameters.function_id ,
1033
- symbol_table,
1034
- object_factory_parameters.string_printable );
1036
+ const bool is_char_sequence =
1037
+ java_string_library_preprocesst
1038
+ ::implements_java_char_sequence (struct_type);
1039
+ const bool has_length_and_data =
1040
+ struct_type.has_component (" length" ) && struct_type.has_component (" data" );
1041
+ const bool has_string_input_values =
1042
+ !object_factory_parameters.string_input_values .empty ();
1043
+
1044
+ if (is_char_sequence && has_length_and_data && has_string_input_values)
1045
+ { // We're dealing with a string and we should set fixed input values.
1046
+ skip_special_string_fields = true ;
1047
+
1048
+ // We create a switch statement where each case is an assignment
1049
+ // of one of the fixed input strings to the input variable in question
1050
+
1051
+ const alternate_casest cases =
1052
+ get_string_input_values_code (
1053
+ expr,
1054
+ object_factory_parameters.string_input_values ,
1055
+ symbol_table);
1056
+ assignments.add (generate_nondet_switch (
1057
+ id2string (object_factory_parameters.function_id ),
1058
+ cases,
1059
+ java_int_type (),
1060
+ ID_java,
1061
+ loc,
1062
+ symbol_table));
1063
+ }
1064
+ else
1065
+ {
1066
+ // Add an initial all-zero write. Most of the fields of this will be
1067
+ // overwritten, but it helps to have a whole-structure write that analysis
1068
+ // passes can easily recognise leaves no uninitialised state behind.
1069
+
1070
+ // This code mirrors the `remove_java_new` pass:
1071
+ auto initial_object =
1072
+ zero_initializer (struct_type, source_locationt (), ns);
1073
+ CHECK_RETURN (initial_object.has_value ());
1074
+ const irep_idt qualified_clsid = " java::" + id2string (class_identifier);
1075
+ set_class_identifier (
1076
+ to_struct_expr (*initial_object), ns, struct_tag_typet (qualified_clsid));
1077
+
1078
+ // If the initialised type is a special-cased String type (one with length
1079
+ // and data fields introduced by string-library preprocessing), initialise
1080
+ // those fields with nondet values
1081
+ if (is_char_sequence && has_length_and_data)
1082
+ { // We're dealing with a string
1083
+ skip_special_string_fields = true ;
1084
+ initialize_nondet_string_fields (
1085
+ to_struct_expr (*initial_object),
1086
+ assignments,
1087
+ object_factory_parameters.min_nondet_string_length ,
1088
+ object_factory_parameters.max_nondet_string_length ,
1089
+ loc,
1090
+ object_factory_parameters.function_id ,
1091
+ symbol_table,
1092
+ object_factory_parameters.string_printable );
1093
+ }
1035
1094
1036
- assignments.add (code_assignt (expr, *initial_object));
1095
+ assignments.add (code_assignt (expr, *initial_object));
1096
+ }
1037
1097
}
1038
1098
1039
1099
for (const auto &component : components)
@@ -1061,8 +1121,7 @@ void java_object_factoryt::gen_nondet_struct_init(
1061
1121
}
1062
1122
else if (skip_special_string_fields && (name == " length" || name == " data" ))
1063
1123
{
1064
- // In this case these were set up by initialise_nondet_string_fields
1065
- // above.
1124
+ // In this case these were set up above.
1066
1125
continue ;
1067
1126
}
1068
1127
else
0 commit comments