diff --git a/src/java_bytecode/java_bytecode_convert_class.cpp b/src/java_bytecode/java_bytecode_convert_class.cpp index 16126efb32f..605a5ddca87 100644 --- a/src/java_bytecode/java_bytecode_convert_class.cpp +++ b/src/java_bytecode/java_bytecode_convert_class.cpp @@ -239,9 +239,19 @@ void java_bytecode_convert_classt::convert(const classt &c) extract_generic_superclass_reference(c.signature); if(superclass_ref.has_value()) { - const java_generic_symbol_typet generic_base( - base, superclass_ref.value(), qualified_classname); - class_type.add_base(generic_base); + try + { + const java_generic_symbol_typet generic_base( + base, superclass_ref.value(), qualified_classname); + class_type.add_base(generic_base); + } + catch(unsupported_java_class_signature_exceptiont) + { + debug() << "unsupported generic superclass signature " + << id2string(*superclass_ref) + << " falling back on using the descriptor" << eom; + class_type.add_base(base); + } } else { @@ -268,9 +278,19 @@ void java_bytecode_convert_classt::convert(const classt &c) extract_generic_interface_reference(c.signature, id2string(interface)); if(interface_ref.has_value()) { - const java_generic_symbol_typet generic_base( - base, interface_ref.value(), qualified_classname); - class_type.add_base(generic_base); + try + { + const java_generic_symbol_typet generic_base( + base, interface_ref.value(), qualified_classname); + class_type.add_base(generic_base); + } + catch(unsupported_java_class_signature_exceptiont) + { + debug() << "unsupported generic interface signature " + << id2string(*interface_ref) + << " falling back on using the descriptor" << eom; + class_type.add_base(base); + } } else { diff --git a/unit/Makefile b/unit/Makefile index 16f985fa47a..20185bd20ed 100644 --- a/unit/Makefile +++ b/unit/Makefile @@ -45,6 +45,7 @@ SRC += unit_tests.cpp \ util/symbol_table.cpp \ catch_example.cpp \ java_bytecode/java_virtual_functions/virtual_functions.cpp \ + java_bytecode/java_bytecode_parse_generics/parse_generic_superclasses.cpp \ # Empty last line INCLUDES= -I ../src/ -I. diff --git a/unit/java_bytecode/java_bytecode_parse_generics/DerivedGenerics.java b/unit/java_bytecode/java_bytecode_parse_generics/DerivedGenerics.java index 6492f0d49dc..caf7bd5e178 100644 --- a/unit/java_bytecode/java_bytecode_parse_generics/DerivedGenerics.java +++ b/unit/java_bytecode/java_bytecode_parse_generics/DerivedGenerics.java @@ -169,3 +169,23 @@ public T someMethod() { return f; } } + +class GenericBounds extends Generic> { + // references exist only to load these class files, too + GenericBoundsUpper gen_upper; + GenericBoundsLower gen_lower; + GenericInterface gen_interface; + +} + +class GenericBoundsUpper extends Generic> { +} + +class GenericBoundsLower extends Generic> { +} + +class GenericInterface implements InterfaceGeneric> { + public Class someMethod(){ + return null; + } +} diff --git a/unit/java_bytecode/java_bytecode_parse_generics/GenericBounds.class b/unit/java_bytecode/java_bytecode_parse_generics/GenericBounds.class new file mode 100644 index 00000000000..50c385d2d67 Binary files /dev/null and b/unit/java_bytecode/java_bytecode_parse_generics/GenericBounds.class differ diff --git a/unit/java_bytecode/java_bytecode_parse_generics/GenericBoundsLower.class b/unit/java_bytecode/java_bytecode_parse_generics/GenericBoundsLower.class new file mode 100644 index 00000000000..76e961d1d51 Binary files /dev/null and b/unit/java_bytecode/java_bytecode_parse_generics/GenericBoundsLower.class differ diff --git a/unit/java_bytecode/java_bytecode_parse_generics/GenericBoundsUpper.class b/unit/java_bytecode/java_bytecode_parse_generics/GenericBoundsUpper.class new file mode 100644 index 00000000000..31a874c0615 Binary files /dev/null and b/unit/java_bytecode/java_bytecode_parse_generics/GenericBoundsUpper.class differ diff --git a/unit/java_bytecode/java_bytecode_parse_generics/GenericInterface.class b/unit/java_bytecode/java_bytecode_parse_generics/GenericInterface.class new file mode 100644 index 00000000000..9a18c2b56fb Binary files /dev/null and b/unit/java_bytecode/java_bytecode_parse_generics/GenericInterface.class differ diff --git a/unit/java_bytecode/java_bytecode_parse_generics/parse_generic_superclasses.cpp b/unit/java_bytecode/java_bytecode_parse_generics/parse_generic_superclasses.cpp new file mode 100644 index 00000000000..dd89cae6aad --- /dev/null +++ b/unit/java_bytecode/java_bytecode_parse_generics/parse_generic_superclasses.cpp @@ -0,0 +1,64 @@ +/*******************************************************************\ + + Module: Unit tests for parsing classes with generic superclasses or interfaces + with unsupported signatures, falling back to using the raw type + descriptors + + Author: DiffBlue Limited. All rights reserved. + +\*******************************************************************/ + +#include +#include +#include + +SCENARIO( + "parse generic superclass signature", + "[core][java_byte code[java_bytecode_parse_generics]]") +{ + const symbol_tablet &new_symbol_table = load_java_class( + "GenericBounds", "./java_bytecode/java_bytecode_parse_generics"); + + const std::string base_generic = "java::Generic"; + const irep_idt base_generic_interface = "java::InterfaceGeneric"; + + const std::string load_class("java::GenericBounds"); + THEN( + "these fields have a non-generic base class / interface as their real " + "generic signature is unsupported at the moment") + { + // once bounds in generic signatures are supported, this test must be + // changed to check for the correct generic types, TODO(mgudemann), + // cf. TG-1286, TG-675 + { + const symbolt &upper_symbol = + new_symbol_table.lookup_ref("java::GenericBoundsUpper"); + const java_class_typet &upper_type = + to_java_class_type(upper_symbol.type); + REQUIRE(upper_type.bases().size() == 1); + const symbol_typet base_type = require_type::require_symbol( + upper_type.bases().at(0).type(), base_generic); + REQUIRE_FALSE(is_java_generic_symbol_type(base_type)); + } + { + const symbolt &lower_symbol = + new_symbol_table.lookup_ref("java::GenericBoundsLower"); + const java_class_typet &lower_type = + to_java_class_type(lower_symbol.type); + REQUIRE(lower_type.bases().size() == 1); + const symbol_typet base_type = require_type::require_symbol( + lower_type.bases().at(0).type(), base_generic); + REQUIRE_FALSE(is_java_generic_symbol_type(base_type)); + } + { + const symbolt &interface_symbol = + new_symbol_table.lookup_ref("java::GenericInterface"); + const java_class_typet &interface_type = + to_java_class_type(interface_symbol.type); + REQUIRE(interface_type.bases().size() == 2); + const symbol_typet base_type = require_type::require_symbol( + interface_type.bases().at(1).type(), base_generic_interface); + REQUIRE_FALSE(is_java_generic_symbol_type(base_type)); + } + } +}