Fri, 16 Oct 2020 23:17:14 +0100
8243302: Advanced class supports
Reviewed-by: mbalao, andrew
1.1 --- a/src/share/vm/classfile/classFileParser.cpp Fri Oct 16 19:25:10 2020 +0100 1.2 +++ b/src/share/vm/classfile/classFileParser.cpp Fri Oct 16 23:17:14 2020 +0100 1.3 @@ -2691,8 +2691,83 @@ 1.4 // Inner classes can be static, private or protected (classic VM does this) 1.5 #define RECOGNIZED_INNER_CLASS_MODIFIERS (JVM_RECOGNIZED_CLASS_MODIFIERS | JVM_ACC_PRIVATE | JVM_ACC_PROTECTED | JVM_ACC_STATIC) 1.6 1.7 +// Find index of the InnerClasses entry for the specified inner_class_info_index. 1.8 +// Return -1 if none is found. 1.9 +static int inner_classes_find_index(const Array<u2>* inner_classes, int inner, const ConstantPool* cp, int length) { 1.10 + Symbol* cp_klass_name = cp->klass_name_at(inner); 1.11 + for (int idx = 0; idx < length; idx += InstanceKlass::inner_class_next_offset) { 1.12 + int idx_inner = inner_classes->at(idx + InstanceKlass::inner_class_inner_class_info_offset); 1.13 + if (cp->klass_name_at(idx_inner) == cp_klass_name) { 1.14 + return idx; 1.15 + } 1.16 + } 1.17 + return -1; 1.18 +} 1.19 + 1.20 +// Return the outer_class_info_index for the InnerClasses entry containing the 1.21 +// specified inner_class_info_index. Return -1 if no InnerClasses entry is found. 1.22 +static int inner_classes_jump_to_outer(const Array<u2>* inner_classes, int inner, const ConstantPool* cp, int length) { 1.23 + if (inner == 0) return -1; 1.24 + int idx = inner_classes_find_index(inner_classes, inner, cp, length); 1.25 + if (idx == -1) return -1; 1.26 + int result = inner_classes->at(idx + InstanceKlass::inner_class_outer_class_info_offset); 1.27 + return result; 1.28 +} 1.29 + 1.30 +// Return true if circularity is found, false if no circularity is found. 1.31 +// Use Floyd's cycle finding algorithm. 1.32 +static bool inner_classes_check_loop_through_outer(const Array<u2>* inner_classes, int idx, const ConstantPool* cp, int length) { 1.33 + int slow = inner_classes->at(idx + InstanceKlass::inner_class_inner_class_info_offset); 1.34 + int fast = inner_classes->at(idx + InstanceKlass::inner_class_outer_class_info_offset); 1.35 + while (fast != -1 && fast != 0) { 1.36 + if (slow != 0 && (cp->klass_name_at(slow) == cp->klass_name_at(fast))) { 1.37 + return true; // found a circularity 1.38 + } 1.39 + fast = inner_classes_jump_to_outer(inner_classes, fast, cp, length); 1.40 + if (fast == -1) return false; 1.41 + fast = inner_classes_jump_to_outer(inner_classes, fast, cp, length); 1.42 + if (fast == -1) return false; 1.43 + slow = inner_classes_jump_to_outer(inner_classes, slow, cp, length); 1.44 + assert(slow != -1, "sanity check"); 1.45 + } 1.46 + return false; 1.47 +} 1.48 + 1.49 +// Loop through each InnerClasses entry checking for circularities and duplications 1.50 +// with other entries. If duplicate entries are found then throw CFE. Otherwise, 1.51 +// return true if a circularity or entries with duplicate inner_class_info_indexes 1.52 +// are found. 1.53 +bool ClassFileParser::check_inner_classes_circularity(const ConstantPool* cp, int length, TRAPS) { 1.54 + // Loop through each InnerClasses entry. 1.55 + for (int idx = 0; idx < length; idx += InstanceKlass::inner_class_next_offset) { 1.56 + // Return true if there are circular entries. 1.57 + if (inner_classes_check_loop_through_outer(_inner_classes, idx, cp, length)) { 1.58 + return true; 1.59 + } 1.60 + // Check if there are duplicate entries or entries with the same inner_class_info_index. 1.61 + for (int y = idx + InstanceKlass::inner_class_next_offset; y < length; 1.62 + y += InstanceKlass::inner_class_next_offset) { 1.63 + 1.64 + // To maintain compatibility, throw an exception if duplicate inner classes 1.65 + // entries are found. 1.66 + guarantee_property((_inner_classes->at(idx) != _inner_classes->at(y) || 1.67 + _inner_classes->at(idx+1) != _inner_classes->at(y+1) || 1.68 + _inner_classes->at(idx+2) != _inner_classes->at(y+2) || 1.69 + _inner_classes->at(idx+3) != _inner_classes->at(y+3)), 1.70 + "Duplicate entry in InnerClasses attribute in class file %s", 1.71 + CHECK_(true)); 1.72 + // Return true if there are two entries with the same inner_class_info_index. 1.73 + if (_inner_classes->at(y) == _inner_classes->at(idx)) { 1.74 + return true; 1.75 + } 1.76 + } 1.77 + } 1.78 + return false; 1.79 +} 1.80 + 1.81 // Return number of classes in the inner classes attribute table 1.82 -u2 ClassFileParser::parse_classfile_inner_classes_attribute(u1* inner_classes_attribute_start, 1.83 +u2 ClassFileParser::parse_classfile_inner_classes_attribute(const ConstantPool* cp, 1.84 + u1* inner_classes_attribute_start, 1.85 bool parsed_enclosingmethod_attribute, 1.86 u2 enclosing_method_class_index, 1.87 u2 enclosing_method_method_index, 1.88 @@ -2764,25 +2839,28 @@ 1.89 } 1.90 1.91 // 4347400: make sure there's no duplicate entry in the classes array 1.92 + // Also, check for circular entries. 1.93 + bool has_circularity = false; 1.94 if (_need_verify && _major_version >= JAVA_1_5_VERSION) { 1.95 - for(int i = 0; i < length * 4; i += 4) { 1.96 - for(int j = i + 4; j < length * 4; j += 4) { 1.97 - guarantee_property((inner_classes->at(i) != inner_classes->at(j) || 1.98 - inner_classes->at(i+1) != inner_classes->at(j+1) || 1.99 - inner_classes->at(i+2) != inner_classes->at(j+2) || 1.100 - inner_classes->at(i+3) != inner_classes->at(j+3)), 1.101 - "Duplicate entry in InnerClasses in class file %s", 1.102 - CHECK_0); 1.103 + has_circularity = check_inner_classes_circularity(cp, length * 4, CHECK_0); 1.104 + if (has_circularity) { 1.105 + // If circularity check failed then ignore InnerClasses attribute. 1.106 + MetadataFactory::free_array<u2>(_loader_data, _inner_classes); 1.107 + index = 0; 1.108 + if (parsed_enclosingmethod_attribute) { 1.109 + inner_classes = MetadataFactory::new_array<u2>(_loader_data, 2, CHECK_0); 1.110 + _inner_classes = inner_classes; 1.111 + } else { 1.112 + _inner_classes = Universe::the_empty_short_array(); 1.113 } 1.114 } 1.115 } 1.116 - 1.117 // Set EnclosingMethod class and method indexes. 1.118 if (parsed_enclosingmethod_attribute) { 1.119 inner_classes->at_put(index++, enclosing_method_class_index); 1.120 inner_classes->at_put(index++, enclosing_method_method_index); 1.121 } 1.122 - assert(index == size, "wrong size"); 1.123 + assert(index == size || has_circularity, "wrong size"); 1.124 1.125 // Restore buffer's current position. 1.126 cfs->set_current(current_mark); 1.127 @@ -3051,6 +3129,7 @@ 1.128 1.129 if (parsed_innerclasses_attribute || parsed_enclosingmethod_attribute) { 1.130 u2 num_of_classes = parse_classfile_inner_classes_attribute( 1.131 + _cp, 1.132 inner_classes_attribute_start, 1.133 parsed_innerclasses_attribute, 1.134 enclosing_method_class_index,
2.1 --- a/src/share/vm/classfile/classFileParser.hpp Fri Oct 16 19:25:10 2020 +0100 2.2 +++ b/src/share/vm/classfile/classFileParser.hpp Fri Oct 16 23:17:14 2020 +0100 2.3 @@ -275,7 +275,12 @@ 2.4 u2 parse_generic_signature_attribute(TRAPS); 2.5 void parse_classfile_sourcefile_attribute(TRAPS); 2.6 void parse_classfile_source_debug_extension_attribute(int length, TRAPS); 2.7 - u2 parse_classfile_inner_classes_attribute(u1* inner_classes_attribute_start, 2.8 + 2.9 + // Check for circularity in InnerClasses attribute. 2.10 + bool check_inner_classes_circularity(const ConstantPool* cp, int length, TRAPS); 2.11 + 2.12 + u2 parse_classfile_inner_classes_attribute(const ConstantPool* cp, 2.13 + u1* inner_classes_attribute_start, 2.14 bool parsed_enclosingmethod_attribute, 2.15 u2 enclosing_method_class_index, 2.16 u2 enclosing_method_method_index,
3.1 --- a/src/share/vm/oops/constantPool.cpp Fri Oct 16 19:25:10 2020 +0100 3.2 +++ b/src/share/vm/oops/constantPool.cpp Fri Oct 16 23:17:14 2020 +0100 3.3 @@ -504,7 +504,7 @@ 3.4 } 3.5 3.6 3.7 -Symbol* ConstantPool::klass_name_at(int which) { 3.8 +Symbol* ConstantPool::klass_name_at(int which) const { 3.9 assert(tag_at(which).is_unresolved_klass() || tag_at(which).is_klass(), 3.10 "Corrupted constant pool"); 3.11 // A resolved constantPool entry will contain a Klass*, otherwise a Symbol*.
4.1 --- a/src/share/vm/oops/constantPool.hpp Fri Oct 16 19:25:10 2020 +0100 4.2 +++ b/src/share/vm/oops/constantPool.hpp Fri Oct 16 23:17:14 2020 +0100 4.3 @@ -125,7 +125,7 @@ 4.4 private: 4.5 intptr_t* base() const { return (intptr_t*) (((char*) this) + sizeof(ConstantPool)); } 4.6 4.7 - CPSlot slot_at(int which) { 4.8 + CPSlot slot_at(int which) const { 4.9 assert(is_within_bounds(which), "index out of bounds"); 4.10 // Uses volatile because the klass slot changes without a lock. 4.11 volatile intptr_t adr = (intptr_t)OrderAccess::load_ptr_acquire(obj_at_addr_raw(which)); 4.12 @@ -353,7 +353,7 @@ 4.13 return klass_at_impl(h_this, which, CHECK_NULL); 4.14 } 4.15 4.16 - Symbol* klass_name_at(int which); // Returns the name, w/o resolving. 4.17 + Symbol* klass_name_at(int which) const; // Returns the name, w/o resolving. 4.18 4.19 Klass* resolved_klass_at(int which) const { // Used by Compiler 4.20 guarantee(tag_at(which).is_klass(), "Corrupted constant pool");