hotspot/src/share/vm/classfile/classFileParser.cpp
changeset 40923 10fe1c28b9f6
parent 40921 cc129ac8e609
child 41669 2091069b6851
child 41544 d77997d3a28b
--- a/hotspot/src/share/vm/classfile/classFileParser.cpp	Wed Sep 07 09:20:10 2016 +0200
+++ b/hotspot/src/share/vm/classfile/classFileParser.cpp	Wed Sep 07 07:19:48 2016 -0400
@@ -5407,6 +5407,59 @@
   debug_only(ik->verify();)
 }
 
+// For an anonymous class that is in the unnamed package, move it to its host class's
+// package by prepending its host class's package name to its class name and setting
+// its _class_name field.
+void ClassFileParser::prepend_host_package_name(const InstanceKlass* host_klass, TRAPS) {
+  ResourceMark rm(THREAD);
+  assert(strrchr(_class_name->as_C_string(), '/') == NULL,
+         "Anonymous class should not be in a package");
+  const char* host_pkg_name =
+    ClassLoader::package_from_name(host_klass->name()->as_C_string(), NULL);
+
+  if (host_pkg_name != NULL) {
+    size_t host_pkg_len = strlen(host_pkg_name);
+    int class_name_len = _class_name->utf8_length();
+    char* new_anon_name =
+      NEW_RESOURCE_ARRAY(char, host_pkg_len + 1 + class_name_len);
+    // Copy host package name and trailing /.
+    strncpy(new_anon_name, host_pkg_name, host_pkg_len);
+    new_anon_name[host_pkg_len] = '/';
+    // Append anonymous class name. The anonymous class name can contain odd
+    // characters.  So, do a strncpy instead of using sprintf("%s...").
+    strncpy(new_anon_name + host_pkg_len + 1, (char *)_class_name->base(), class_name_len);
+
+    // Create a symbol and update the anonymous class name.
+    _class_name = SymbolTable::new_symbol(new_anon_name,
+                                          (int)host_pkg_len + 1 + class_name_len,
+                                          CHECK);
+  }
+}
+
+// If the host class and the anonymous class are in the same package then do
+// nothing.  If the anonymous class is in the unnamed package then move it to its
+// host's package.  If the classes are in different packages then throw an IAE
+// exception.
+void ClassFileParser::fix_anonymous_class_name(TRAPS) {
+  assert(_host_klass != NULL, "Expected an anonymous class");
+
+  const jbyte* anon_last_slash = UTF8::strrchr(_class_name->base(),
+                                               _class_name->utf8_length(), '/');
+  if (anon_last_slash == NULL) {  // Unnamed package
+    prepend_host_package_name(_host_klass, CHECK);
+  } else {
+    if (!InstanceKlass::is_same_class_package(_host_klass->class_loader(),
+                                              _host_klass->name(),
+                                              _host_klass->class_loader(),
+                                              _class_name)) {
+      ResourceMark rm(THREAD);
+      THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
+        err_msg("Host class %s and anonymous class %s are in different packages",
+        _host_klass->name()->as_C_string(), _class_name->as_C_string()));
+    }
+  }
+}
+
 static bool relax_format_check_for(ClassLoaderData* loader_data) {
   bool trusted = (loader_data->is_the_null_class_loader_data() ||
                   SystemDictionary::is_platform_class_loader(loader_data->class_loader()));
@@ -5422,7 +5475,7 @@
                                  Symbol* name,
                                  ClassLoaderData* loader_data,
                                  Handle protection_domain,
-                                 const Klass* host_klass,
+                                 const InstanceKlass* host_klass,
                                  GrowableArray<Handle>* cp_patches,
                                  Publicity pub_level,
                                  TRAPS) :
@@ -5697,6 +5750,13 @@
     return;
   }
 
+  // if this is an anonymous class fix up its name if it's in the unnamed
+  // package.  Otherwise, throw IAE if it is in a different package than
+  // its host class.
+  if (_host_klass != NULL) {
+    fix_anonymous_class_name(CHECK);
+  }
+
   // Verification prevents us from creating names with dots in them, this
   // asserts that that's the case.
   assert(is_internal_format(_class_name), "external class name format used internally");