Skip to content

Commit 1ad6b5d

Browse files
authored
Merge pull request diffblue#2754 from antlechner/antonia/ci-lazy-loading-rec-clinit
Fix lazy loading of enum static initializers
2 parents 03bdf37 + df0605e commit 1ad6b5d

File tree

10 files changed

+56
-21
lines changed

10 files changed

+56
-21
lines changed
800 Bytes
Binary file not shown.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
public enum Color {
2+
RED,
3+
GREEN,
4+
BLUE
5+
}
Binary file not shown.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
public class MyClass {
2+
3+
private Color c;
4+
5+
public int myMethod() {
6+
if (c == null)
7+
return 10;
8+
return 20;
9+
}
10+
11+
}
Binary file not shown.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
public class NondetEnumArgField {
2+
3+
public static void test(MyClass mc) {
4+
int result = mc.myMethod();
5+
assert result == 10;
6+
}
7+
8+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
CORE
2+
NondetEnumArgField.class
3+
--function NondetEnumArgField.test --cp `../../../../scripts/format_classpath.sh . ../../../src/java_bytecode/library/core-models.jar`
4+
^VERIFICATION FAILED$
5+
--
6+
--
7+
The test checks that even when none of the enum constants are referenced in user
8+
code, a nondet enum (in this case, a field of an argument) is still correctly
9+
loaded and initialized.

jbmc/src/java_bytecode/ci_lazy_methods.cpp

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -382,16 +382,6 @@ void ci_lazy_methodst::initialize_instantiated_classes(
382382
if(param.type().id()==ID_pointer)
383383
{
384384
const pointer_typet &original_pointer = to_pointer_type(param.type());
385-
const auto &original_type = ns.follow(original_pointer.subtype());
386-
// Special case for enums. We may want to generalise this, see TG-4689
387-
// and the comment in java_object_factoryt::gen_nondet_pointer_init.
388-
if(
389-
can_cast_type<java_class_typet>(original_type) &&
390-
to_java_class_type(original_type).get_base("java::java.lang.Enum"))
391-
{
392-
add_clinit_call_for_pointer_type(
393-
original_pointer, ns.get_symbol_table(), needed_lazy_methods);
394-
}
395385
needed_lazy_methods.add_all_needed_classes(original_pointer);
396386
}
397387
}
@@ -407,28 +397,35 @@ void ci_lazy_methodst::initialize_instantiated_classes(
407397
// As in class_loader, ensure these classes stay available
408398
for(const auto &id : extra_instantiated_classes)
409399
needed_lazy_methods.add_needed_class("java::" + id2string(id));
400+
401+
// Special case for enums. We may want to generalise this, see TG-4689
402+
// and the comment in java_object_factoryt::gen_nondet_pointer_init.
403+
for(const auto &found_class : needed_lazy_methods.get_instantiated_classes())
404+
{
405+
const auto &class_type = to_java_class_type(ns.lookup(found_class).type);
406+
if(class_type.get_base("java::java.lang.Enum"))
407+
add_clinit_call(found_class, ns.get_symbol_table(), needed_lazy_methods);
408+
}
410409
}
411410

412411
/// Helper function for `initialize_instantiated_classes`.
413-
/// For a given pointer_typet that is being noted as needed in
414-
/// `needed_lazy_methods`, notes that its static initializer is also needed.
415-
/// This applies the same logic to the class of `pointer_type` that
412+
/// For a given class id that is being noted as needed in `needed_lazy_methods`,
413+
/// notes that its static initializer is also needed.
414+
/// This applies the same logic to the given class that
416415
/// `java_bytecode_convert_methodt::get_clinit_call` applies e.g. to classes
417416
/// whose constructor we call in a method body. This duplication is unavoidable
418417
/// due to the fact that ci_lazy_methods essentially has to go through the same
419418
/// logic as __CPROVER_start in its initial setup.
420-
/// \param pointer_type: The given pointer_typet
419+
/// \param class_id: The given class id
421420
/// \param symbol_table: Used to look up occurrences of static initializers
422421
/// \param [out] needed_lazy_methods: Gets notified of any static initializers
423422
/// that need to be loaded
424-
void ci_lazy_methodst::add_clinit_call_for_pointer_type(
425-
const pointer_typet &pointer_type,
423+
void ci_lazy_methodst::add_clinit_call(
424+
const irep_idt &class_id,
426425
const symbol_tablet &symbol_table,
427426
ci_lazy_methods_neededt &needed_lazy_methods)
428427
{
429-
const irep_idt &pointer_id =
430-
to_symbol_type(pointer_type.subtype()).get_identifier();
431-
const irep_idt &clinit_wrapper = clinit_wrapper_name(pointer_id);
428+
const irep_idt &clinit_wrapper = clinit_wrapper_name(class_id);
432429
if(symbol_table.symbols.count(clinit_wrapper))
433430
needed_lazy_methods.add_needed_method(clinit_wrapper);
434431
}

jbmc/src/java_bytecode/ci_lazy_methods.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,8 @@ class ci_lazy_methodst:public messaget
120120
const namespacet &ns,
121121
ci_lazy_methods_neededt &needed_lazy_methods);
122122

123-
void add_clinit_call_for_pointer_type(
124-
const pointer_typet &pointer_type,
123+
void add_clinit_call(
124+
const irep_idt &class_id,
125125
const symbol_tablet &symbol_table,
126126
ci_lazy_methods_neededt &needed_lazy_methods);
127127

jbmc/src/java_bytecode/ci_lazy_methods_needed.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ class ci_lazy_methods_neededt
3434
pointer_type_selector(pointer_type_selector)
3535
{}
3636

37+
std::unordered_set<irep_idt> get_instantiated_classes()
38+
{
39+
return instantiated_classes;
40+
}
41+
3742
void add_needed_method(const irep_idt &);
3843
// Returns true if new
3944
bool add_needed_class(const irep_idt &);

0 commit comments

Comments
 (0)