Skip to content

Commit bd5ef6e

Browse files
committed
Always run clinit_wrapper before nondet object init
This is more consistent with the behaviour of the JDK (the Java language specification says that static initializers should be run on object initialization), and a necessary requirement to access enum constants.
1 parent 195d402 commit bd5ef6e

File tree

1 file changed

+46
-15
lines changed

1 file changed

+46
-15
lines changed

jbmc/src/java_bytecode/java_object_factory.cpp

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -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 code_typet &type = to_code_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 code_typet &type = to_code_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

Comments
 (0)