# HG changeset patch # User dcherepanov # Date 1592835471 0 # Node ID 5e770b08bd337b48cbac0ce8c37bf1403c853d68 # Parent b878345a286627da1b5f6f2be869de4a4a6408f3 8243302: Advanced class supports Reviewed-by: bae, yan diff -r b878345a2866 -r 5e770b08bd33 src/share/vm/classfile/classFileParser.cpp --- a/src/share/vm/classfile/classFileParser.cpp Wed Sep 23 17:34:10 2020 +0300 +++ b/src/share/vm/classfile/classFileParser.cpp Mon Jun 22 14:17:51 2020 +0000 @@ -2556,6 +2556,80 @@ // Inner classes can be static, private or protected (classic VM does this) #define RECOGNIZED_INNER_CLASS_MODIFIERS (JVM_RECOGNIZED_CLASS_MODIFIERS | JVM_ACC_PRIVATE | JVM_ACC_PROTECTED | JVM_ACC_STATIC) +// Find index of the InnerClasses entry for the specified inner_class_info_index. +// Return -1 if none is found. +static int inner_classes_find_index(typeArrayHandle inner_classes, int inner, constantPoolHandle cp, int length) { + Symbol* cp_klass_name = cp->klass_name_at(inner); + for (int idx = 0; idx < length; idx += instanceKlass::inner_class_next_offset) { + int idx_inner = inner_classes->ushort_at(idx + instanceKlass::inner_class_inner_class_info_offset); + if (cp->klass_name_at(idx_inner) == cp_klass_name) { + return idx; + } + } + return -1; +} + +// Return the outer_class_info_index for the InnerClasses entry containing the +// specified inner_class_info_index. Return -1 if no InnerClasses entry is found. +static int inner_classes_jump_to_outer(typeArrayHandle inner_classes, int inner, constantPoolHandle cp, int length) { + if (inner == 0) return -1; + int idx = inner_classes_find_index(inner_classes, inner, cp, length); + if (idx == -1) return -1; + int result = inner_classes->ushort_at(idx + instanceKlass::inner_class_outer_class_info_offset); + return result; +} + +// Return true if circularity is found, false if no circularity is found. +// Use Floyd's cycle finding algorithm. +static bool inner_classes_check_loop_through_outer(typeArrayHandle inner_classes, int idx, constantPoolHandle cp, int length) { + int slow = inner_classes->ushort_at(idx + instanceKlass::inner_class_inner_class_info_offset); + int fast = inner_classes->ushort_at(idx + instanceKlass::inner_class_outer_class_info_offset); + while (fast != -1 && fast != 0) { + if (slow != 0 && (cp->klass_name_at(slow) == cp->klass_name_at(fast))) { + return true; // found a circularity + } + fast = inner_classes_jump_to_outer(inner_classes, fast, cp, length); + if (fast == -1) return false; + fast = inner_classes_jump_to_outer(inner_classes, fast, cp, length); + if (fast == -1) return false; + slow = inner_classes_jump_to_outer(inner_classes, slow, cp, length); + assert(slow != -1, "sanity check"); + } + return false; +} + +// Loop through each InnerClasses entry checking for circularities and duplications +// with other entries. If duplicate entries are found then throw CFE. Otherwise, +// return true if a circularity or entries with duplicate inner_class_info_indexes +// are found. +bool ClassFileParser::check_inner_classes_circularity(constantPoolHandle cp, int length, TRAPS) { + // Loop through each InnerClasses entry. + for (int idx = 0; idx < length; idx += instanceKlass::inner_class_next_offset) { + // Return true if there are circular entries. + if (inner_classes_check_loop_through_outer(_inner_classes, idx, cp, length)) { + return true; + } + // Check if there are duplicate entries or entries with the same inner_class_info_index. + for (int y = idx + instanceKlass::inner_class_next_offset; y < length; + y += instanceKlass::inner_class_next_offset) { + + // To maintain compatibility, throw an exception if duplicate inner classes + // entries are found. + guarantee_property((_inner_classes->ushort_at(idx) != _inner_classes->ushort_at(y) || + _inner_classes->ushort_at(idx+1) != _inner_classes->ushort_at(y+1) || + _inner_classes->ushort_at(idx+2) != _inner_classes->ushort_at(y+2) || + _inner_classes->ushort_at(idx+3) != _inner_classes->ushort_at(y+3)), + "Duplicate entry in InnerClasses attribute in class file %s", + CHECK_(true)); + // Return true if there are two entries with the same inner_class_info_index. + if (_inner_classes->ushort_at(y) == _inner_classes->ushort_at(idx)) { + return true; + } + } + } + return false; +} + // Return number of classes in the inner classes attribute table u2 ClassFileParser::parse_classfile_inner_classes_attribute(u1* inner_classes_attribute_start, bool parsed_enclosingmethod_attribute, @@ -2584,6 +2658,7 @@ int size = length * 4 + (parsed_enclosingmethod_attribute ? 2 : 0); typeArrayOop ic = oopFactory::new_permanent_shortArray(size, CHECK_0); typeArrayHandle inner_classes(THREAD, ic); + set_class_inner_classes(inner_classes); int index = 0; int cp_size = cp->length(); cfs->guarantee_more(8 * length, CHECK_0); // 4-tuples of u2 @@ -2632,15 +2707,17 @@ } // 4347400: make sure there's no duplicate entry in the classes array + bool has_circularity = false; if (_need_verify && _major_version >= JAVA_1_5_VERSION) { - for(int i = 0; i < length * 4; i += 4) { - for(int j = i + 4; j < length * 4; j += 4) { - guarantee_property((inner_classes->ushort_at(i) != inner_classes->ushort_at(j) || - inner_classes->ushort_at(i+1) != inner_classes->ushort_at(j+1) || - inner_classes->ushort_at(i+2) != inner_classes->ushort_at(j+2) || - inner_classes->ushort_at(i+3) != inner_classes->ushort_at(j+3)), - "Duplicate entry in InnerClasses in class file %s", - CHECK_0); + has_circularity = check_inner_classes_circularity(cp, length * 4, CHECK_0); + if (has_circularity) { + // If circularity check failed then ignore InnerClasses attribute. + index = 0; + if (parsed_enclosingmethod_attribute) { + ic = oopFactory::new_permanent_shortArray(size, CHECK_0); + inner_classes = typeArrayHandle(THREAD, ic); + } else { + inner_classes = Universe::the_empty_short_array(); } } } @@ -2650,7 +2727,7 @@ inner_classes->short_at_put(index++, enclosing_method_class_index); inner_classes->short_at_put(index++, enclosing_method_method_index); } - assert(index == size, "wrong size"); + assert(index == size || has_circularity, "wrong size"); // Update instanceKlass with inner class info. set_class_inner_classes(inner_classes); diff -r b878345a2866 -r 5e770b08bd33 src/share/vm/classfile/classFileParser.hpp --- a/src/share/vm/classfile/classFileParser.hpp Wed Sep 23 17:34:10 2020 +0300 +++ b/src/share/vm/classfile/classFileParser.hpp Mon Jun 22 14:17:51 2020 +0000 @@ -205,6 +205,10 @@ u2 parse_generic_signature_attribute(constantPoolHandle cp, TRAPS); void parse_classfile_sourcefile_attribute(constantPoolHandle cp, TRAPS); void parse_classfile_source_debug_extension_attribute(constantPoolHandle cp, int length, TRAPS); + + // Check for circularity in InnerClasses attribute. + bool check_inner_classes_circularity(constantPoolHandle cp, int length, TRAPS); + u2 parse_classfile_inner_classes_attribute(u1* inner_classes_attribute_start, bool parsed_enclosingmethod_attribute, u2 enclosing_method_class_index,