@@ -148,6 +148,11 @@ class java_object_factoryt
148148 const pointer_typet &substitute_pointer_type,
149149 size_t depth,
150150 const source_locationt &location);
151+
152+ void gen_method_call_if_present (
153+ code_blockt &assignments,
154+ const exprt &instance_expr,
155+ const irep_idt &method_name);
151156};
152157
153158// / Generates code for allocating a dynamic object. This is used in
@@ -764,6 +769,24 @@ void java_object_factoryt::gen_nondet_pointer_init(
764769 }
765770 }
766771
772+ // If this is a void* we *must* initialise with null:
773+ // (This can currently happen for some cases of #exception_value)
774+ bool must_be_null = subtype == empty_typet ();
775+
776+ // If we may be about to initialize a non-null object, always run the
777+ // clinit_wrapper of its class first.
778+ // Note that it would be more consistent with the behaviour of the JVM to only
779+ // run clinit_wrapper if we are about to initialize an object of which we know
780+ // for sure that it is not null on any following branch. However, adding this
781+ // case in gen_nondet_struct_init would slow symex down too much.
782+ if (!must_be_null)
783+ {
784+ const java_class_typet &class_type = to_java_class_type (subtype);
785+ const irep_idt &class_name = class_type.get_name ();
786+ const irep_idt class_clinit = clinit_wrapper_name (class_name);
787+ gen_method_call_if_present (assignments, expr, class_clinit);
788+ }
789+
767790 code_blockt new_object_assignments;
768791 code_blockt update_in_place_assignments;
769792
@@ -810,10 +833,6 @@ void java_object_factoryt::gen_nondet_pointer_init(
810833 const bool allow_null =
811834 depth > object_factory_parameters.max_nonnull_tree_depth ;
812835
813- // Alternatively, if this is a void* we *must* initialise with null:
814- // (This can currently happen for some cases of #exception_value)
815- bool must_be_null = subtype == empty_typet ();
816-
817836 if (must_be_null)
818837 {
819838 // Add the following code to assignments:
@@ -1081,17 +1100,7 @@ void java_object_factoryt::gen_nondet_struct_init(
10811100
10821101 const irep_idt init_method_name =
10831102 " java::" + id2string (struct_tag) + " .cproverNondetInitialize:()V" ;
1084-
1085- if (const auto func = symbol_table.lookup (init_method_name))
1086- {
1087- const java_method_typet &type = to_java_method_type (func->type );
1088- code_function_callt fun_call;
1089- fun_call.function () = func->symbol_expr ();
1090- if (type.has_this ())
1091- fun_call.arguments ().push_back (address_of_exprt (expr));
1092-
1093- assignments.add (fun_call);
1094- }
1103+ gen_method_call_if_present (assignments, expr, init_method_name);
10951104}
10961105
10971106// / Initializes a primitive-typed or reference-typed object tree rooted at
@@ -1619,3 +1628,25 @@ void gen_nondet_init(
16191628 pointer_type_selector,
16201629 update_in_place);
16211630}
1631+
1632+ // / Adds a call for the given method to the end of `assignments` if the method
1633+ // / exists in the symbol table. Does nothing if the method does not exist.
1634+ // / \param assignments: A code block that the method call will be appended to.
1635+ // / \param instance_expr: The instance to call the method on. This argument is
1636+ // / ignored if the method is static.
1637+ // / \param method_name: The name of the method to be called.
1638+ void java_object_factoryt::gen_method_call_if_present (
1639+ code_blockt &assignments,
1640+ const exprt &instance_expr,
1641+ const irep_idt &method_name)
1642+ {
1643+ if (const auto func = symbol_table.lookup (method_name))
1644+ {
1645+ const java_method_typet &type = to_java_method_type (func->type );
1646+ code_function_callt fun_call;
1647+ fun_call.function () = func->symbol_expr ();
1648+ if (type.has_this ())
1649+ fun_call.arguments ().push_back (address_of_exprt (instance_expr));
1650+ assignments.add (fun_call);
1651+ }
1652+ }
0 commit comments