changeset 5889:5e770b08bd33

8243302: Advanced class supports Reviewed-by: bae, yan
author dcherepanov
date Mon, 22 Jun 2020 14:17:51 +0000
parents b878345a2866
children 25cc4aea4eb4
files src/share/vm/classfile/classFileParser.cpp src/share/vm/classfile/classFileParser.hpp
diffstat 2 files changed, 90 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- 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);
--- 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,