Skip to content

Commit cc6136b

Browse files
committed
CI lazy methods: load clinit for all enum types
Previously static initializers for enum types were only loaded for those types that are reachable from the arguments to the entry method. This would lead to an invariant violation when an opaque method returned an enum type (which needs to be nondet-initialized just like arguments to the entry method). This commit solves this problem by moving the code for marking the static initializers of enums as loaded from ci_lazy_methods to ci_lazy_methods_needed, and applying it to all deterministic and nondeterministic enums that are reachable in some way from the entry method. Including deterministic enums is not a problem, since we load static initializers for all types (enums and others) whose constructor we use anyway.
1 parent f1489fd commit cc6136b

File tree

4 files changed

+30
-41
lines changed

4 files changed

+30
-41
lines changed

jbmc/src/java_bytecode/ci_lazy_methods.cpp

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -392,37 +392,6 @@ void ci_lazy_methodst::initialize_instantiated_classes(
392392
// As in class_loader, ensure these classes stay available
393393
for(const auto &id : extra_instantiated_classes)
394394
needed_lazy_methods.add_needed_class("java::" + id2string(id));
395-
396-
// Special case for enums. We may want to generalise this, see TG-4689
397-
// and the comment in java_object_factoryt::gen_nondet_pointer_init.
398-
for(const auto &found_class : needed_lazy_methods.get_instantiated_classes())
399-
{
400-
const auto &class_type = to_java_class_type(ns.lookup(found_class).type);
401-
if(class_type.get_base("java::java.lang.Enum"))
402-
add_clinit_call(found_class, ns.get_symbol_table(), needed_lazy_methods);
403-
}
404-
}
405-
406-
/// Helper function for `initialize_instantiated_classes`.
407-
/// For a given class id that is being noted as needed in `needed_lazy_methods`,
408-
/// notes that its static initializer is also needed.
409-
/// This applies the same logic to the given class that
410-
/// `java_bytecode_convert_methodt::get_clinit_call` applies e.g. to classes
411-
/// whose constructor we call in a method body. This duplication is unavoidable
412-
/// due to the fact that ci_lazy_methods essentially has to go through the same
413-
/// logic as __CPROVER_start in its initial setup.
414-
/// \param class_id: The given class id
415-
/// \param symbol_table: Used to look up occurrences of static initializers
416-
/// \param [out] needed_lazy_methods: Gets notified of any static initializers
417-
/// that need to be loaded
418-
void ci_lazy_methodst::add_clinit_call(
419-
const irep_idt &class_id,
420-
const symbol_tablet &symbol_table,
421-
ci_lazy_methods_neededt &needed_lazy_methods)
422-
{
423-
const irep_idt &clinit_wrapper = clinit_wrapper_name(class_id);
424-
if(symbol_table.symbols.count(clinit_wrapper))
425-
needed_lazy_methods.add_needed_method(clinit_wrapper);
426395
}
427396

428397
/// Get places where virtual functions are called.

jbmc/src/java_bytecode/ci_lazy_methods.h

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

123-
void add_clinit_call(
124-
const irep_idt &class_id,
125-
const symbol_tablet &symbol_table,
126-
ci_lazy_methods_neededt &needed_lazy_methods);
127-
128123
void gather_virtual_callsites(
129124
const exprt &e,
130125
std::unordered_set<exprt, irep_hash> &result);

jbmc/src/java_bytecode/ci_lazy_methods_needed.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ Author: Chris Smowton, [email protected]
1010
/// Context-insensitive lazy methods container
1111

1212
#include "ci_lazy_methods.h"
13+
#include "java_static_initializers.h"
1314

1415
#include <java_bytecode/select_pointer_type.h>
1516
#include <string>
@@ -25,6 +26,24 @@ void ci_lazy_methods_neededt::add_needed_method(
2526
callable_methods.insert(method_symbol_name);
2627
}
2728

29+
/// For a given class id, note that its static initializer is needed.
30+
/// This applies the same logic to the given class that
31+
/// `java_bytecode_convert_methodt::get_clinit_call` applies e.g. to classes
32+
/// whose constructor we call in a method body. This duplication is unavoidable
33+
/// because ci_lazy_methods essentially has to go through the same logic as
34+
/// __CPROVER_start in its initial setup, and because return values of opaque
35+
/// methods need to be considered in ci_lazy_methods too.
36+
/// \param class_id: The given class id
37+
/// \param symbol_table: Used to look up occurrences of static initializers
38+
void ci_lazy_methods_neededt::add_clinit_call(
39+
const irep_idt &class_id,
40+
const symbol_tablet &symbol_table)
41+
{
42+
const irep_idt &clinit_wrapper = clinit_wrapper_name(class_id);
43+
if(symbol_table.symbols.count(clinit_wrapper))
44+
add_needed_method(clinit_wrapper);
45+
}
46+
2847
/// Notes class `class_symbol_name` will be instantiated, or a static field
2948
/// belonging to it will be accessed. Also notes that its static initializer is
3049
/// therefore reachable.
@@ -42,6 +61,14 @@ bool ci_lazy_methods_neededt::add_needed_class(
4261
if(symbol_table.symbols.count(cprover_validate))
4362
add_needed_method(cprover_validate);
4463

64+
// Special case for enums. We may want to generalise this, the comment in
65+
// \ref java_object_factoryt::gen_nondet_pointer_init (TG-4689).
66+
namespacet ns(symbol_table);
67+
const auto &class_type =
68+
to_java_class_type(ns.lookup(class_symbol_name).type);
69+
if(class_type.get_base("java::java.lang.Enum"))
70+
add_clinit_call(class_symbol_name, symbol_table);
71+
4572
return true;
4673
}
4774

jbmc/src/java_bytecode/ci_lazy_methods_needed.h

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

38-
std::unordered_set<irep_idt> get_instantiated_classes()
39-
{
40-
return instantiated_classes;
41-
}
42-
4338
void add_needed_method(const irep_idt &);
4439
// Returns true if new
4540
bool add_needed_class(const irep_idt &);
@@ -61,6 +56,9 @@ class ci_lazy_methods_neededt
6156

6257
const select_pointer_typet &pointer_type_selector;
6358

59+
void
60+
add_clinit_call(const irep_idt &class_id, const symbol_tablet &symbol_table);
61+
6462
void initialize_instantiated_classes_from_pointer(
6563
const pointer_typet &pointer_type,
6664
const namespacet &ns);

0 commit comments

Comments
 (0)