< prev index next >

src/hotspot/share/oops/instanceKlass.cpp

Print this page

        

@@ -148,20 +148,20 @@
 // called to verify that k is a member of this nest
 bool InstanceKlass::has_nest_member(InstanceKlass* k, TRAPS) const {
   if (_nest_members == NULL || _nest_members == Universe::the_empty_short_array()) {
     if (log_is_enabled(Trace, class, nestmates)) {
       ResourceMark rm(THREAD);
-      log_trace(class, nestmates)("Checking nest membership of %s in non-nest-host class %s",
-                                  k->name()->as_C_string(), this->name()->as_C_string());
+      log_trace(class, nestmates)("Checked nest membership of %s in non-nest-host class %s",
+                                  k->external_name(), this->external_name());
     }
     return false;
   }
 
   if (log_is_enabled(Trace, class, nestmates)) {
     ResourceMark rm(THREAD);
     log_trace(class, nestmates)("Checking nest membership of %s in %s",
-                                k->name()->as_C_string(), this->name()->as_C_string());
+                                k->external_name(), this->external_name());
   }
 
   // Check names first and if they match then check actual klass. This avoids
   // resolving anything unnecessarily.
   for (int i = 0; i < _nest_members->length(); i++) {

@@ -172,120 +172,170 @@
 
       // names match so check actual klass - this may trigger class loading if
       // it doesn't match (but that should be impossible)
       Klass* k2 = _constants->klass_at(cp_index, CHECK_false);
       if (k2 == k) {
-        log_trace(class, nestmates)("- klass is nestmate member");
+        log_trace(class, nestmates)("- class is listed as a nest member");
         return true;
       }
       else {
         // same name but different klass!
         log_trace(class, nestmates)(" - klass comparison failed!");
       }
     }
   }
-  log_trace(class, nestmates)("- klass is NOT nestmate member!");
+  log_trace(class, nestmates)("- class is NOT a nest member!");
   return false;
 }
 
-// Return nest-host class, resolving, validating and saving it if needed
+// 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
+// causes the access check to return false. Such code will retry the access
+// from a more suitable environment later.
 InstanceKlass* InstanceKlass::nest_host(TRAPS) {
   InstanceKlass* nest_host_k = _nest_host;
   if (nest_host_k == NULL) {
     // need to resolve and save our nest-host class. This could be attempted
     // concurrently but as the result is idempotent and we don't use the class
     // then we do not need any synchronization beyond what is implicitly used
     // during class loading.
     if (_nest_host_index != 0) { // we have a real nest_host
+      // Before trying to resolve check if we're in a suitable context
+      if (!THREAD->can_call_java() && !_constants->tag_at(_nest_host_index).is_klass()) {
       if (log_is_enabled(Trace, class, nestmates)) {
         ResourceMark rm(THREAD);
-        log_trace(class, nestmates)("Resolving nest-host of %s using cp entry for %s",
-                                    this->name()->as_C_string(),
-                                    _constants->klass_name_at(_nest_host_index)->as_C_string());
+          log_trace(class, nestmates)("Rejected resolution of nest-host of %s in unsuitable thread",
+                                      this->external_name());
+        }
+        return NULL;
       }
-
-      Klass* k = _constants->klass_at(_nest_host_index, CHECK_NULL);
 
       if (log_is_enabled(Trace, class, nestmates)) {
         ResourceMark rm(THREAD);
-        log_trace(class, nestmates)("Resolved nest-host of %s to %s",
-                                    this->name()->as_C_string(), k->name()->as_C_string());
+        log_trace(class, nestmates)("Resolving nest-host of %s using cp entry for %s",
+                                    this->external_name(),
+                                    _constants->klass_name_at(_nest_host_index)->as_C_string());
       }
 
-      if (!k->is_instance_klass()) {
-        ResourceMark rm(THREAD);
-        Exceptions::fthrow(
-                           THREAD_AND_LOCATION,
-                           vmSymbols::java_lang_IncompatibleClassChangeError(),
-                           "class %s has non-instance class %s as nest-host",
-                           this->external_name(),
-                           k->external_name()
-                           );
+      Klass* k = _constants->klass_at(_nest_host_index, THREAD);
+      if (HAS_PENDING_EXCEPTION) {
+        Handle exc_h = Handle(THREAD, PENDING_EXCEPTION);
+        if (exc_h->is_a(SystemDictionary::NoClassDefFoundError_klass())) {
+          // throw a new CDNFE with the original as its cause, and a clear msg
+          ResourceMark rm(THREAD);
+          char buf[200];
+          CLEAR_PENDING_EXCEPTION;
+          jio_snprintf(buf, sizeof(buf),
+                       "Unable to load nest-host class of %s",
+                       this->external_name());
+          log_trace(class, nestmates)("%s - NoClassDefFoundError", buf);
+          THROW_MSG_CAUSE_NULL(vmSymbols::java_lang_NoClassDefFoundError(), buf, exc_h);
+        }
+        // other exceptions pass through (OOME, StackOverflowError etc)
         return NULL;
       }
 
+      // A valid nest-host is an instance class in the current package that lists this
+      // class as a nest member. If any of these conditions are not met we simply throw
+      // IllegalAccessError, with a suitable message.
+
+      const char* error = NULL;
+
+      // Need to check we have an instance class first
+      if (k->is_instance_klass()) {
       nest_host_k = InstanceKlass::cast(k);
 
+        // FIXME: an exception from this is perhaps impossible
       bool is_member = nest_host_k->has_nest_member(this, CHECK_NULL);
-      if (!is_member) {
-        // this_k and nest_host disagree about nest membership
+        if (is_member) {
+          // Finally check we're in the same package - as there could be collusion
+          // between untrusted types.
+          if (is_same_class_package(nest_host_k)) {
+            // save resolved nest-host value
+            _nest_host = nest_host_k;
+
+            if (log_is_enabled(Trace, class, nestmates)) {
         ResourceMark rm(THREAD);
-        Exceptions::fthrow(
-                           THREAD_AND_LOCATION,
-                           vmSymbols::java_lang_IncompatibleClassChangeError(),
-                           "Type %s is not a nest member of %s",
+              log_trace(class, nestmates)("Resolved nest-host of %s to %s",
+                                          this->external_name(), k->external_name());
+            }
+            return nest_host_k;
+          }
+          else {
+            error = "types are in different packages";
+          }
+        }
+        else {
+          error = "current type is not listed as a nest member";
+        }
+      }
+      else {
+        error = "nest-host is not an instance class!";
+      }
+
+      if (log_is_enabled(Trace, class, nestmates)) {
+        ResourceMark rm(THREAD);
+        log_trace(class, nestmates)("Type %s is not a nest member of resolved type %s: %s",
                            this->external_name(),
-                           nest_host_k->external_name()
-                           );
-        return NULL;
+                                    k->external_name(),
+                                    error);
       }
 
-      if (!is_same_class_package(nest_host_k)) {
         ResourceMark rm(THREAD);
-        Exceptions::fthrow(
-                           THREAD_AND_LOCATION,
-                           vmSymbols::java_lang_IncompatibleClassChangeError(),
-                           "Class %s is in a different package to its nest-host class %s",
+      Exceptions::fthrow(THREAD_AND_LOCATION,
+                         vmSymbols::java_lang_IllegalAccessError(),
+                         "Type %s is not a nest member of %s: %s",
                            this->external_name(),
-                           nest_host_k->external_name()
+                         k->external_name(),
+                         error
                            );
         return NULL;
       }
-    }
     else {
       if (log_is_enabled(Trace, class, nestmates)) {
         ResourceMark rm(THREAD);
-        log_trace(class, nestmates)("Class %s is not part of a nest: setting nest-host to self",
-                                    this->name()->as_C_string());
+        log_trace(class, nestmates)("Type %s is not part of a nest: setting nest-host to self",
+                                    this->external_name());
       }
-      nest_host_k = const_cast<InstanceKlass*>(this);
+      // save resolved nest-host value
+      return (_nest_host = this);
     }
   }
-  // save resolved nest-host value
-  _nest_host = nest_host_k;
-
   return nest_host_k;
 }
 
 // check if 'this' and k are nestmates (same nest_host), or k is our nest_host,
 // or we are k's nest_host - all of which is covered by comparing the two
 // resolved_nest_hosts
 bool InstanceKlass::has_nestmate_access_to(InstanceKlass* k, TRAPS) {
 
-  // If not actually nestmates, then both nest-host classes may have to loaded
-  // and the nest membership of each class validated.
-  InstanceKlass* cur_top = nest_host(CHECK_false);
-  Klass* k_nest_host = k->nest_host(CHECK_false);
+  assert(this != k, "this should be handled by higher-level code");
+
+  // Per the JVMS we first resolve and validate the current class, then
+  // the target class k. Resolution exceptions will be passed on by upper
+  // layers. IllegalAccessErrors from membership validation failures will
+  // also be passed through.
+
+  InstanceKlass* cur_host = nest_host(THREAD);
+  if (cur_host == NULL || HAS_PENDING_EXCEPTION) {
+    return false;
+  }
+
+  Klass* k_nest_host = k->nest_host(THREAD);
+  if (k_nest_host == NULL || HAS_PENDING_EXCEPTION) {
+    return false;
+  }
 
-  bool access = (cur_top == k_nest_host);
+  bool access = (cur_host == k_nest_host);
 
   if (log_is_enabled(Trace, class, nestmates)) {
     ResourceMark rm(THREAD);
     log_trace(class, nestmates)("Class %s does %shave nestmate accesss to %s",
-                                this->name()->as_C_string(),
+                                this->external_name(),
                                 access ? "" : "NOT ",
-                                k->name()->as_C_string());
+                                k->external_name());
   }
 
   return access;
 }
 
< prev index next >