changeset 53758:d7daab4641d8 sealed

make the verifier allow subtyping of sealed classes
author vromero
date Wed, 12 Dec 2018 10:48:20 -0500
parents e70eb090a5f3
children 25a9f833a8e4
files src/hotspot/share/classfile/classFileParser.cpp src/hotspot/share/classfile/classFileParser.hpp src/hotspot/share/logging/logTag.hpp src/hotspot/share/oops/instanceKlass.cpp src/hotspot/share/oops/instanceKlass.hpp
diffstat 5 files changed, 68 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/src/hotspot/share/classfile/classFileParser.cpp	Mon Dec 10 20:54:10 2018 -0500
+++ b/src/hotspot/share/classfile/classFileParser.cpp	Wed Dec 12 10:48:20 2018 -0500
@@ -5830,6 +5830,8 @@
   // it's official
   set_klass(ik);
 
+  check_subtyping(CHECK);
+
   debug_only(ik->verify();)
 }
 
@@ -6391,10 +6393,6 @@
       );
       return;
     }
-    // Make sure super class is not final
-    if (_super_klass->is_final()) {
-      THROW_MSG(vmSymbols::java_lang_VerifyError(), "Cannot inherit from final class");
-    }
   }
 
   // Compute the transitive list of all unique interfaces implemented by this class
@@ -6439,6 +6437,18 @@
 
 }
 
+void ClassFileParser::check_subtyping(TRAPS) {
+  assert(NULL != _klass, "_klass should have been resolved before calling this method");
+  if (_super_klass != NULL) {
+    if (_super_klass->is_final()) {
+      bool isPermittedSubtype = _super_klass->has_as_permitted_subtype(_klass, CHECK);
+      if (!isPermittedSubtype) {
+        THROW_MSG(vmSymbols::java_lang_VerifyError(), "Cannot inherit from final class");
+      }
+    }
+  }
+}
+
 void ClassFileParser::set_klass(InstanceKlass* klass) {
 
 #ifdef ASSERT
--- a/src/hotspot/share/classfile/classFileParser.hpp	Mon Dec 10 20:54:10 2018 -0500
+++ b/src/hotspot/share/classfile/classFileParser.hpp	Wed Dec 12 10:48:20 2018 -0500
@@ -501,6 +501,9 @@
                      FieldLayoutInfo* info,
                      TRAPS);
 
+  // check that the current class is not extending a final class or interface
+  void check_subtyping(TRAPS);
+
  public:
   ClassFileParser(ClassFileStream* stream,
                   Symbol* name,
--- a/src/hotspot/share/logging/logTag.hpp	Mon Dec 10 20:54:10 2018 -0500
+++ b/src/hotspot/share/logging/logTag.hpp	Wed Dec 12 10:48:20 2018 -0500
@@ -137,6 +137,7 @@
   LOG_TAG(safepoint) \
   LOG_TAG(sampling) \
   LOG_TAG(scavenge) \
+  LOG_TAG(sealed) \
   LOG_TAG(setting) \
   LOG_TAG(smr) \
   LOG_TAG(stacktrace) \
--- a/src/hotspot/share/oops/instanceKlass.cpp	Mon Dec 10 20:54:10 2018 -0500
+++ b/src/hotspot/share/oops/instanceKlass.cpp	Wed Dec 12 10:48:20 2018 -0500
@@ -201,6 +201,53 @@
   return false;
 }
 
+// Called to verify that k is a permitted subtype of this class
+bool InstanceKlass::has_as_permitted_subtype(InstanceKlass* k, TRAPS) const {
+  if (k == NULL) {
+    if (log_is_enabled(Trace, class, sealed)) {
+      ResourceMark rm(THREAD);
+      log_trace(class, sealed)("Checked for permitted subtype of %s with a NULL instance class", this->external_name());
+    }
+    return false;
+  }
+  if (_permitted_subtypes == NULL || _permitted_subtypes == Universe::the_empty_short_array()) {
+    if (log_is_enabled(Trace, class, sealed)) {
+      ResourceMark rm(THREAD);
+      log_trace(class, sealed)("Checked for permitted subtype of %s in non-sealed class %s",
+                                  k->external_name(), this->external_name());
+    }
+    return false;
+  }
+
+  if (log_is_enabled(Trace, class, sealed)) {
+    ResourceMark rm(THREAD);
+    log_trace(class, sealed)("Checking for permitted subtype of %s in %s",
+                                k->external_name(), this->external_name());
+  }
+
+  // Check for a resolved cp entry, else fall back to a name check.
+  // We don't want to resolve any class other than the one being checked.
+  for (int i = 0; i < _permitted_subtypes->length(); i++) {
+    int cp_index = _permitted_subtypes->at(i);
+    if (_constants->tag_at(cp_index).is_klass()) {
+      Klass* k2 = _constants->klass_at(cp_index, CHECK_false);
+      if (k2 == k) {
+        log_trace(class, sealed)("- class is listed at permitted_subtypes[%d] => cp[%d]", i, cp_index);
+        return true;
+      }
+    }
+    else {
+      Symbol* name = _constants->klass_name_at(cp_index);
+      if (name == k->name()) {
+        log_trace(class, sealed)("- Found it at permitted_subtypes[%d] => cp[%d]", i, cp_index);
+        return true;
+      }
+    }
+  }
+  log_trace(class, sealed)("- class is NOT a permitted subtype!");
+  return false;
+}
+
 // Return nest-host class, resolving, validating and saving it if needed.
 // In cases where this is called from a thread that can not do classloading
 // (such as a native JIT thread) then we simply return NULL, which in turn
--- a/src/hotspot/share/oops/instanceKlass.hpp	Mon Dec 10 20:54:10 2018 -0500
+++ b/src/hotspot/share/oops/instanceKlass.hpp	Wed Dec 12 10:48:20 2018 -0500
@@ -469,6 +469,9 @@
 private:
   // Called to verify that k is a member of this nest - does not look at k's nest-host
   bool has_nest_member(InstanceKlass* k, TRAPS) const;
+
+  // Called to verify that k is a permitted subtype of this class
+  bool has_as_permitted_subtype(InstanceKlass* k, TRAPS) const;
 public:
   // Returns nest-host class, resolving and validating it if needed
   // Returns NULL if an exception occurs during loading, or validation fails