Skip to content

Commit b3967eb

Browse files
Antonia LechnerAntonia Lechner
Antonia Lechner
authored and
Antonia Lechner
committed
Fix strings not being recognized in the object factory
For a given struct, the object factory previously checked if it was a string only in the case where skip_classid was set to false and the update strategy was NO_UPDATE_IN_PLACE or MAY_UPDATE_IN_PLACE. This missed some cases, for example the case where no model for String is loaded and the Java method includes a call to a string constructor that depends on a model. In this case the constructor is stubbed and skip_classid is set to true in java_simple_method_stubst. Before this fix, the object factory would go through the components of the string expression as if it was a regular object expression, and hit an invariant violation because the data component is stored as a pointer to an unsignedbv, contradicting the assumption that all pointers point to structs.
1 parent c312a18 commit b3967eb

File tree

1 file changed

+59
-67
lines changed

1 file changed

+59
-67
lines changed

jbmc/src/java_bytecode/java_object_factory.cpp

Lines changed: 59 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -794,77 +794,69 @@ void java_object_factoryt::gen_nondet_struct_init(
794794
// * Not if the object has already been initialised by our caller, in which
795795
// case they will set `skip_classid`
796796
// * Not if we're re-initializing an existing object (i.e. update_in_place)
797-
798-
bool skip_special_string_fields = false;
799-
800-
if(!is_sub &&
801-
!skip_classid &&
802-
update_in_place != update_in_placet::MUST_UPDATE_IN_PLACE)
797+
// * Always if it has a string type. Strings should not be partially updated,
798+
// and the `length` and `data` components of string types need to be
799+
// generated differently from object fields in the general case, see
800+
// \ref java_object_factoryt::initialize_nondet_string_fields.
801+
802+
const bool is_char_sequence =
803+
java_string_library_preprocesst::implements_java_char_sequence(struct_type);
804+
const bool has_length_and_data =
805+
struct_type.has_component("length") && struct_type.has_component("data");
806+
const bool skip_special_string_fields =
807+
is_char_sequence && has_length_and_data;
808+
const bool has_string_input_values =
809+
!object_factory_parameters.string_input_values.empty();
810+
811+
if(skip_special_string_fields && has_string_input_values && !skip_classid)
812+
{ // We're dealing with a string and we should set fixed input values.
813+
// We create a switch statement where each case is an assignment
814+
// of one of the fixed input strings to the input variable in question
815+
const alternate_casest cases = get_string_input_values_code(
816+
expr, object_factory_parameters.string_input_values, symbol_table);
817+
assignments.add(generate_nondet_switch(
818+
id2string(object_factory_parameters.function_id),
819+
cases,
820+
java_int_type(),
821+
ID_java,
822+
location,
823+
symbol_table));
824+
}
825+
else if(
826+
(!is_sub && !skip_classid &&
827+
update_in_place != update_in_placet::MUST_UPDATE_IN_PLACE) ||
828+
skip_special_string_fields)
803829
{
804-
class_identifier = struct_tag;
830+
// Add an initial all-zero write. Most of the fields of this will be
831+
// overwritten, but it helps to have a whole-structure write that analysis
832+
// passes can easily recognise leaves no uninitialised state behind.
805833

806-
const bool is_char_sequence =
807-
java_string_library_preprocesst
808-
::implements_java_char_sequence(struct_type);
809-
const bool has_length_and_data =
810-
struct_type.has_component("length") && struct_type.has_component("data");
811-
const bool has_string_input_values =
812-
!object_factory_parameters.string_input_values.empty();
813-
814-
if(is_char_sequence && has_length_and_data && has_string_input_values)
815-
{ // We're dealing with a string and we should set fixed input values.
816-
skip_special_string_fields = true;
817-
818-
// We create a switch statement where each case is an assignment
819-
// of one of the fixed input strings to the input variable in question
820-
821-
const alternate_casest cases =
822-
get_string_input_values_code(
823-
expr,
824-
object_factory_parameters.string_input_values,
825-
symbol_table);
826-
assignments.add(generate_nondet_switch(
827-
id2string(object_factory_parameters.function_id),
828-
cases,
829-
java_int_type(),
830-
ID_java,
834+
// This code mirrors the `remove_java_new` pass:
835+
auto initial_object = zero_initializer(expr.type(), source_locationt(), ns);
836+
CHECK_RETURN(initial_object.has_value());
837+
class_identifier = struct_tag;
838+
const irep_idt qualified_clsid = "java::" + id2string(class_identifier);
839+
set_class_identifier(
840+
to_struct_expr(*initial_object), ns, struct_tag_typet(qualified_clsid));
841+
842+
// If the initialised type is a special-cased String type (one with length
843+
// and data fields introduced by string-library preprocessing), initialise
844+
// those fields with nondet values
845+
if(skip_special_string_fields)
846+
{ // We're dealing with a string
847+
initialize_nondet_string_fields(
848+
to_struct_expr(*initial_object),
849+
assignments,
850+
object_factory_parameters.min_nondet_string_length,
851+
object_factory_parameters.max_nondet_string_length,
831852
location,
832-
symbol_table));
833-
}
834-
else
835-
{
836-
// Add an initial all-zero write. Most of the fields of this will be
837-
// overwritten, but it helps to have a whole-structure write that analysis
838-
// passes can easily recognise leaves no uninitialised state behind.
839-
840-
// This code mirrors the `remove_java_new` pass:
841-
auto initial_object =
842-
zero_initializer(expr.type(), source_locationt(), ns);
843-
CHECK_RETURN(initial_object.has_value());
844-
const irep_idt qualified_clsid = "java::" + id2string(class_identifier);
845-
set_class_identifier(
846-
to_struct_expr(*initial_object), ns, struct_tag_typet(qualified_clsid));
847-
848-
// If the initialised type is a special-cased String type (one with length
849-
// and data fields introduced by string-library preprocessing), initialise
850-
// those fields with nondet values
851-
if(is_char_sequence && has_length_and_data)
852-
{ // We're dealing with a string
853-
skip_special_string_fields = true;
854-
initialize_nondet_string_fields(
855-
to_struct_expr(*initial_object),
856-
assignments,
857-
object_factory_parameters.min_nondet_string_length,
858-
object_factory_parameters.max_nondet_string_length,
859-
location,
860-
object_factory_parameters.function_id,
861-
symbol_table,
862-
object_factory_parameters.string_printable,
863-
allocate_objects);
864-
}
865-
866-
assignments.add(code_assignt(expr, *initial_object));
853+
object_factory_parameters.function_id,
854+
symbol_table,
855+
object_factory_parameters.string_printable,
856+
allocate_objects);
867857
}
858+
859+
assignments.add(code_assignt(expr, *initial_object));
868860
}
869861

870862
for(const auto &component : components)

0 commit comments

Comments
 (0)