@@ -3087,8 +3087,83 @@ void ClassFileParser::parse_classfile_source_debug_extension_attribute(const Cla
3087
3087
JVM_ACC_STATIC \
3088
3088
)
3089
3089
3090
+ // Find index of the InnerClasses entry for the specified inner_class_info_index.
3091
+ // Return -1 if none is found.
3092
+ static int inner_classes_find_index (const Array<u2>* inner_classes, int inner, const ConstantPool* cp, int length) {
3093
+ Symbol* cp_klass_name = cp->klass_name_at (inner);
3094
+ for (int idx = 0 ; idx < length; idx += InstanceKlass::inner_class_next_offset) {
3095
+ int idx_inner = inner_classes->at (idx + InstanceKlass::inner_class_inner_class_info_offset);
3096
+ if (cp->klass_name_at (idx_inner) == cp_klass_name) {
3097
+ return idx;
3098
+ }
3099
+ }
3100
+ return -1 ;
3101
+ }
3102
+
3103
+ // Return the outer_class_info_index for the InnerClasses entry containing the
3104
+ // specified inner_class_info_index. Return -1 if no InnerClasses entry is found.
3105
+ static int inner_classes_jump_to_outer (const Array<u2>* inner_classes, int inner, const ConstantPool* cp, int length) {
3106
+ if (inner == 0 ) return -1 ;
3107
+ int idx = inner_classes_find_index (inner_classes, inner, cp, length);
3108
+ if (idx == -1 ) return -1 ;
3109
+ int result = inner_classes->at (idx + InstanceKlass::inner_class_outer_class_info_offset);
3110
+ return result;
3111
+ }
3112
+
3113
+ // Return true if circularity is found, false if no circularity is found.
3114
+ // Use Floyd's cycle finding algorithm.
3115
+ static bool inner_classes_check_loop_through_outer (const Array<u2>* inner_classes, int idx, const ConstantPool* cp, int length) {
3116
+ int slow = inner_classes->at (idx + InstanceKlass::inner_class_inner_class_info_offset);
3117
+ int fast = inner_classes->at (idx + InstanceKlass::inner_class_outer_class_info_offset);
3118
+ while (fast != -1 && fast != 0 ) {
3119
+ if (slow != 0 && (cp->klass_name_at (slow) == cp->klass_name_at (fast))) {
3120
+ return true ; // found a circularity
3121
+ }
3122
+ fast = inner_classes_jump_to_outer (inner_classes, fast, cp, length);
3123
+ if (fast == -1 ) return false ;
3124
+ fast = inner_classes_jump_to_outer (inner_classes, fast, cp, length);
3125
+ if (fast == -1 ) return false ;
3126
+ slow = inner_classes_jump_to_outer (inner_classes, slow, cp, length);
3127
+ assert (slow != -1 , " sanity check" );
3128
+ }
3129
+ return false ;
3130
+ }
3131
+
3132
+ // Loop through each InnerClasses entry checking for circularities and duplications
3133
+ // with other entries. If duplicate entries are found then throw CFE. Otherwise,
3134
+ // return true if a circularity or entries with duplicate inner_class_info_indexes
3135
+ // are found.
3136
+ bool ClassFileParser::check_inner_classes_circularity (const ConstantPool* cp, int length, TRAPS) {
3137
+ // Loop through each InnerClasses entry.
3138
+ for (int idx = 0 ; idx < length; idx += InstanceKlass::inner_class_next_offset) {
3139
+ // Return true if there are circular entries.
3140
+ if (inner_classes_check_loop_through_outer (_inner_classes, idx, cp, length)) {
3141
+ return true ;
3142
+ }
3143
+ // Check if there are duplicate entries or entries with the same inner_class_info_index.
3144
+ for (int y = idx + InstanceKlass::inner_class_next_offset; y < length;
3145
+ y += InstanceKlass::inner_class_next_offset) {
3146
+
3147
+ // To maintain compatibility, throw an exception if duplicate inner classes
3148
+ // entries are found.
3149
+ guarantee_property ((_inner_classes->at (idx) != _inner_classes->at (y) ||
3150
+ _inner_classes->at (idx+1 ) != _inner_classes->at (y+1 ) ||
3151
+ _inner_classes->at (idx+2 ) != _inner_classes->at (y+2 ) ||
3152
+ _inner_classes->at (idx+3 ) != _inner_classes->at (y+3 )),
3153
+ " Duplicate entry in InnerClasses attribute in class file %s" ,
3154
+ CHECK_ (true ));
3155
+ // Return true if there are two entries with the same inner_class_info_index.
3156
+ if (_inner_classes->at (y) == _inner_classes->at (idx)) {
3157
+ return true ;
3158
+ }
3159
+ }
3160
+ }
3161
+ return false ;
3162
+ }
3163
+
3090
3164
// Return number of classes in the inner classes attribute table
3091
3165
u2 ClassFileParser::parse_classfile_inner_classes_attribute (const ClassFileStream* const cfs,
3166
+ const ConstantPool* cp,
3092
3167
const u1* const inner_classes_attribute_start,
3093
3168
bool parsed_enclosingmethod_attribute,
3094
3169
u2 enclosing_method_class_index,
@@ -3112,7 +3187,7 @@ u2 ClassFileParser::parse_classfile_inner_classes_attribute(const ClassFileStrea
3112
3187
// enclosing_method_class_index,
3113
3188
// enclosing_method_method_index]
3114
3189
const int size = length * 4 + (parsed_enclosingmethod_attribute ? 2 : 0 );
3115
- Array<u2>* const inner_classes = MetadataFactory::new_array<u2>(_loader_data, size, CHECK_0);
3190
+ Array<u2>* inner_classes = MetadataFactory::new_array<u2>(_loader_data, size, CHECK_0);
3116
3191
_inner_classes = inner_classes;
3117
3192
3118
3193
int index = 0 ;
@@ -3163,25 +3238,28 @@ u2 ClassFileParser::parse_classfile_inner_classes_attribute(const ClassFileStrea
3163
3238
}
3164
3239
3165
3240
// 4347400: make sure there's no duplicate entry in the classes array
3241
+ // Also, check for circular entries.
3242
+ bool has_circularity = false ;
3166
3243
if (_need_verify && _major_version >= JAVA_1_5_VERSION) {
3167
- for (int i = 0 ; i < length * 4 ; i += 4 ) {
3168
- for (int j = i + 4 ; j < length * 4 ; j += 4 ) {
3169
- guarantee_property ((inner_classes->at (i) != inner_classes->at (j) ||
3170
- inner_classes->at (i+1 ) != inner_classes->at (j+1 ) ||
3171
- inner_classes->at (i+2 ) != inner_classes->at (j+2 ) ||
3172
- inner_classes->at (i+3 ) != inner_classes->at (j+3 )),
3173
- " Duplicate entry in InnerClasses in class file %s" ,
3174
- CHECK_0);
3244
+ has_circularity = check_inner_classes_circularity (cp, length * 4 , CHECK_0);
3245
+ if (has_circularity) {
3246
+ // If circularity check failed then ignore InnerClasses attribute.
3247
+ MetadataFactory::free_array<u2>(_loader_data, _inner_classes);
3248
+ index = 0 ;
3249
+ if (parsed_enclosingmethod_attribute) {
3250
+ inner_classes = MetadataFactory::new_array<u2>(_loader_data, 2 , CHECK_0);
3251
+ _inner_classes = inner_classes;
3252
+ } else {
3253
+ _inner_classes = Universe::the_empty_short_array ();
3175
3254
}
3176
3255
}
3177
3256
}
3178
-
3179
3257
// Set EnclosingMethod class and method indexes.
3180
3258
if (parsed_enclosingmethod_attribute) {
3181
3259
inner_classes->at_put (index++, enclosing_method_class_index);
3182
3260
inner_classes->at_put (index++, enclosing_method_method_index);
3183
3261
}
3184
- assert (index == size, " wrong size" );
3262
+ assert (index == size || has_circularity , " wrong size" );
3185
3263
3186
3264
// Restore buffer's current position.
3187
3265
cfs->set_current (current_mark);
@@ -3564,6 +3642,7 @@ void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cf
3564
3642
if (parsed_innerclasses_attribute || parsed_enclosingmethod_attribute) {
3565
3643
const u2 num_of_classes = parse_classfile_inner_classes_attribute (
3566
3644
cfs,
3645
+ cp,
3567
3646
inner_classes_attribute_start,
3568
3647
parsed_innerclasses_attribute,
3569
3648
enclosing_method_class_index,
0 commit comments