Skip to content

Commit 6f98511

Browse files
author
Thomas Kiley
authored
Merge pull request diffblue#2335 from thk123/bugfix/load-classes-from-opaque-calls
Load classes from opaque calls [TG-3657]
2 parents c0dd633 + e95f59d commit 6f98511

20 files changed

+220
-163
lines changed
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
public class Bar {
2+
public int x;
3+
4+
public void cproverNondetInitialize() {
5+
6+
}
7+
}
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
public class Baz {
2+
public void cproverNondetInitialize() {
3+
4+
}
5+
}
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
public class Foo {
2+
public Bar subType;
3+
4+
public Baz[] arraySubtype;
5+
6+
public Gen<GenFiller> genSubtype;
7+
8+
public void cproverNondetInitialize() {
9+
10+
}
11+
}
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
public class Gen<T> {
2+
T t;
3+
}
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
public class GenFiller {
2+
public int i;
3+
4+
public void cproverNondetInitialize() {
5+
6+
}
7+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
public class Opaque
2+
{
3+
static Foo opaqueMethod() {
4+
return null;
5+
}
6+
}
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
public class TestClass {
2+
public static void testFunction() {
3+
int x = Opaque.opaqueMethod().subType.x;
4+
}
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
CORE symex-driven-lazy-loading-expected-failure
2+
TestClass.class
3+
--function TestClass.testFunction --lazy-methods --verbosity 10
4+
CI lazy methods: elaborate java::Foo\.cproverNondetInitialize:\(\)V
5+
CI lazy methods: elaborate java::Bar\.cproverNondetInitialize:\(\)V
6+
CI lazy methods: elaborate java::Baz\.cproverNondetInitialize:\(\)V
7+
CI lazy methods: elaborate java::GenFiller\.cproverNondetInitialize:\(\)V
8+
--
9+
--
10+
Testing that the return type of an opaque method is correctly elaborated. The
11+
cproverNondetInitialize should be loaded for all classes where an instance might
12+
be seen.
13+
This doesn't work under symex-driven lazy loading because it is incompatible with --lazy-methods

jbmc/src/java_bytecode/ci_lazy_methods.cpp

+9-142
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,10 @@ bool ci_lazy_methodst::operator()(
113113
{
114114
std::unordered_set<irep_idt> initial_callable_methods;
115115
ci_lazy_methods_neededt initial_lazy_methods(
116-
initial_callable_methods, instantiated_classes, symbol_table);
116+
initial_callable_methods,
117+
instantiated_classes,
118+
symbol_table,
119+
pointer_type_selector);
117120
initialize_instantiated_classes(
118121
methods_to_convert_later, namespacet(symbol_table), initial_lazy_methods);
119122
methods_to_convert_later.insert(
@@ -174,17 +177,6 @@ bool ci_lazy_methodst::operator()(
174177
symbol_table);
175178
}
176179

177-
// cproverNondetInitialize has to be force-loaded for mocks to return valid
178-
// objects (objects which satisfy invariants specified in the
179-
// cproverNondetInitialize method)
180-
for(const auto &class_name : instantiated_classes)
181-
{
182-
const irep_idt cprover_validate =
183-
id2string(class_name) + ".cproverNondetInitialize:()V";
184-
if(symbol_table.symbols.count(cprover_validate))
185-
methods_already_populated.insert(cprover_validate);
186-
}
187-
188180
// Remove symbols for methods that were declared but never used:
189181
symbol_tablet keep_symbols;
190182
// Manually keep @inflight_exception, as it is unused at this stage
@@ -298,7 +290,10 @@ ci_lazy_methodst::convert_and_analyze_method(
298290
// Note this wraps *references* to methods_to_convert_later &
299291
// instantiated_classes
300292
ci_lazy_methods_neededt needed_methods(
301-
methods_to_convert_later, instantiated_classes, symbol_table);
293+
methods_to_convert_later,
294+
instantiated_classes,
295+
symbol_table,
296+
pointer_type_selector);
302297

303298
const bool could_not_convert_function =
304299
method_converter(method_name, needed_methods);
@@ -430,8 +425,7 @@ void ci_lazy_methodst::initialize_instantiated_classes(
430425
if(param.type().id()==ID_pointer)
431426
{
432427
const pointer_typet &original_pointer=to_pointer_type(param.type());
433-
initialize_all_instantiated_classes_from_pointer(
434-
original_pointer, ns, needed_lazy_methods);
428+
needed_lazy_methods.add_all_needed_classes(original_pointer);
435429
}
436430
}
437431
}
@@ -448,75 +442,6 @@ void ci_lazy_methodst::initialize_instantiated_classes(
448442
needed_lazy_methods.add_needed_class("java::" + id2string(id));
449443
}
450444

451-
/// Build up list of methods for types for a pointer and any types it
452-
/// might be subsituted for. See
453-
/// `initialize_instantiated_classes` for more details.
454-
/// \param pointer_type: The type to gather methods for.
455-
/// \param ns: global namespace
456-
/// \param [out] needed_lazy_methods: Populated with all Java reference types
457-
/// whose references may be passed, directly or indirectly, to any of the
458-
/// functions in `entry_points`
459-
void ci_lazy_methodst::initialize_all_instantiated_classes_from_pointer(
460-
const pointer_typet &pointer_type,
461-
const namespacet &ns,
462-
ci_lazy_methods_neededt &needed_lazy_methods)
463-
{
464-
initialize_instantiated_classes_from_pointer(
465-
pointer_type,
466-
ns,
467-
needed_lazy_methods);
468-
469-
// TODO we should be passing here a map that maps generic parameters
470-
// to concrete types in the current context TG-2664
471-
const pointer_typet &subbed_pointer_type =
472-
pointer_type_selector.convert_pointer_type(pointer_type, {}, ns);
473-
474-
if(subbed_pointer_type!=pointer_type)
475-
{
476-
initialize_instantiated_classes_from_pointer(
477-
subbed_pointer_type, ns, needed_lazy_methods);
478-
}
479-
}
480-
481-
/// Build up list of methods for types for a specific pointer type. See
482-
/// `initialize_instantiated_classes` for more details.
483-
/// \param pointer_type: The type to gather methods for.
484-
/// \param ns: global namespace
485-
/// \param [out] needed_lazy_methods: Populated with all Java reference types
486-
/// whose references may be passed, directly or indirectly, to any of the
487-
/// functions in `entry_points`
488-
void ci_lazy_methodst::initialize_instantiated_classes_from_pointer(
489-
const pointer_typet &pointer_type,
490-
const namespacet &ns,
491-
ci_lazy_methods_neededt &needed_lazy_methods)
492-
{
493-
const symbol_typet &class_type=to_symbol_type(pointer_type.subtype());
494-
const auto &param_classid=class_type.get_identifier();
495-
496-
// Note here: different arrays may have different element types, so we should
497-
// explore again even if we've seen this classid before in the array case.
498-
if(needed_lazy_methods.add_needed_class(param_classid) ||
499-
is_java_array_tag(param_classid))
500-
{
501-
gather_field_types(pointer_type.subtype(), ns, needed_lazy_methods);
502-
}
503-
504-
if(is_java_generic_type(pointer_type))
505-
{
506-
// Assume if this is a generic like X<A, B, C>, then any concrete parameters
507-
// will at some point be instantiated.
508-
const auto &generic_args =
509-
to_java_generic_type(pointer_type).generic_type_arguments();
510-
for(const auto &generic_arg : generic_args)
511-
{
512-
if(!is_java_generic_parameter(generic_arg))
513-
{
514-
initialize_instantiated_classes_from_pointer(
515-
generic_arg, ns, needed_lazy_methods);
516-
}
517-
}
518-
}
519-
}
520445

521446
/// Get places where virtual functions are called.
522447
/// \param e: expression tree to search
@@ -611,64 +536,6 @@ void ci_lazy_methodst::gather_needed_globals(
611536
gather_needed_globals(*opit, symbol_table, needed);
612537
}
613538

614-
/// See param needed_lazy_methods
615-
/// \param class_type: root of class tree to search
616-
/// \param ns: global namespace
617-
/// \param [out] needed_lazy_methods: Popualted with all Java reference types
618-
/// reachable starting at `class_type`. For example if `class_type` is
619-
/// `symbol_typet("java::A")` and A has a B field, then `B` (but not `A`) will
620-
/// noted as a needed class.
621-
void ci_lazy_methodst::gather_field_types(
622-
const typet &class_type,
623-
const namespacet &ns,
624-
ci_lazy_methods_neededt &needed_lazy_methods)
625-
{
626-
const auto &underlying_type=to_struct_type(ns.follow(class_type));
627-
if(is_java_array_tag(underlying_type.get_tag()))
628-
{
629-
// If class_type is not a symbol this may be a reference array,
630-
// but we can't tell what type.
631-
if(class_type.id() == ID_symbol)
632-
{
633-
const typet &element_type =
634-
java_array_element_type(to_symbol_type(class_type));
635-
if(element_type.id() == ID_pointer)
636-
{
637-
// This is a reference array -- mark its element type available.
638-
initialize_all_instantiated_classes_from_pointer(
639-
to_pointer_type(element_type), ns, needed_lazy_methods);
640-
}
641-
}
642-
}
643-
else
644-
{
645-
for(const auto &field : underlying_type.components())
646-
{
647-
if(field.type().id() == ID_struct || field.type().id() == ID_symbol)
648-
gather_field_types(field.type(), ns, needed_lazy_methods);
649-
else if(field.type().id() == ID_pointer)
650-
{
651-
if(field.type().subtype().id() == ID_symbol)
652-
{
653-
initialize_all_instantiated_classes_from_pointer(
654-
to_pointer_type(field.type()), ns, needed_lazy_methods);
655-
}
656-
else
657-
{
658-
// If raw structs were possible this would lead to missed
659-
// dependencies, as both array element and specialised generic type
660-
// information cannot be obtained in this case.
661-
// We should therefore only be skipping pointers such as the uint16t*
662-
// in our internal String representation.
663-
INVARIANT(
664-
field.type().subtype().id() != ID_struct,
665-
"struct types should be referred to by symbol at this stage");
666-
}
667-
}
668-
}
669-
}
670-
}
671-
672539
/// Find a virtual callee, if one is defined and the callee type is known to
673540
/// exist.
674541
/// \param instantiated_classes: set of classes that can be instantiated.

jbmc/src/java_bytecode/ci_lazy_methods.h

-15
Original file line numberDiff line numberDiff line change
@@ -121,16 +121,6 @@ class ci_lazy_methodst:public messaget
121121
const namespacet &ns,
122122
ci_lazy_methods_neededt &needed_lazy_methods);
123123

124-
void initialize_all_instantiated_classes_from_pointer(
125-
const pointer_typet &pointer_type,
126-
const namespacet &ns,
127-
ci_lazy_methods_neededt &needed_lazy_methods);
128-
129-
void initialize_instantiated_classes_from_pointer(
130-
const pointer_typet &pointer_type,
131-
const namespacet &ns,
132-
ci_lazy_methods_neededt &needed_lazy_methods);
133-
134124
void gather_virtual_callsites(
135125
const exprt &e,
136126
std::unordered_set<exprt, irep_hash> &result);
@@ -146,11 +136,6 @@ class ci_lazy_methodst:public messaget
146136
const symbol_tablet &symbol_table,
147137
symbol_tablet &needed);
148138

149-
void gather_field_types(
150-
const typet &class_type,
151-
const namespacet &ns,
152-
ci_lazy_methods_neededt &needed_lazy_methods);
153-
154139
irep_idt get_virtual_method_target(
155140
const std::unordered_set<irep_idt> &instantiated_classes,
156141
const irep_idt &call_basename,

0 commit comments

Comments
 (0)