8205533: Class.getPackage() fails with InternalError if class is defined to the bootstrap class loader but module is not in the boot layer
authoralanb
Sun, 24 Jun 2018 16:25:47 +0100
changeset 50744 6c306d54366d
parent 50743 e7519209f7ff
child 50745 a390cbb82d47
8205533: Class.getPackage() fails with InternalError if class is defined to the bootstrap class loader but module is not in the boot layer Reviewed-by: mchung
src/java.base/share/classes/jdk/internal/loader/BootLoader.java
src/java.base/share/classes/jdk/internal/module/Modules.java
test/jdk/java/lang/Class/GetPackageBootLoaderChildLayer.java
--- a/src/java.base/share/classes/jdk/internal/loader/BootLoader.java	Sun Jun 24 15:02:08 2018 +0300
+++ b/src/java.base/share/classes/jdk/internal/loader/BootLoader.java	Sun Jun 24 16:25:47 2018 +0100
@@ -44,6 +44,7 @@
 
 import jdk.internal.misc.JavaLangAccess;
 import jdk.internal.misc.SharedSecrets;
+import jdk.internal.module.Modules;
 import jdk.internal.module.ServicesCatalog;
 
 /**
@@ -249,15 +250,16 @@
                 }
             }
 
+            // return the Module object for the module name. The Module may
+            // in the boot layer or a child layer for the case that the module
+            // is loaded into a running VM
             if (mn != null) {
-                // named module from runtime image or exploded module
-                Optional<Module> om = ModuleLayer.boot().findModule(mn);
-                if (!om.isPresent())
-                    throw new InternalError(mn + " not in boot layer");
-                return om.get();
+                String name = mn;
+                return Modules.findLoadedModule(mn)
+                    .orElseThrow(() -> new InternalError(name + " not loaded"));
+            } else {
+                return null;
             }
-
-            return null;
         }
 
         /**
--- a/src/java.base/share/classes/jdk/internal/module/Modules.java	Sun Jun 24 15:02:08 2018 +0300
+++ b/src/java.base/share/classes/jdk/internal/module/Modules.java	Sun Jun 24 16:25:47 2018 +0100
@@ -35,6 +35,7 @@
 import java.security.PrivilegedAction;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.Set;
 import java.util.function.Function;
 import java.util.stream.Collectors;
@@ -249,7 +250,19 @@
 
     }
 
-    // the top-most system layer
-    private static ModuleLayer topLayer;
+    /**
+     * Finds the module with the given name in the boot layer or any child
+     * layers created to load the "java.instrument" or "jdk.management.agent"
+     * modules into a running VM.
+     */
+    public static Optional<Module> findLoadedModule(String name) {
+        ModuleLayer top = topLayer;
+        if (top == null)
+            top = ModuleLayer.boot();
+        return top.findModule(name);
+    }
+
+    // the top-most layer
+    private static volatile ModuleLayer topLayer;
 
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/Class/GetPackageBootLoaderChildLayer.java	Sun Jun 24 16:25:47 2018 +0100
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @modules jdk.attach
+ * @run main/othervm --limit-modules jdk.attach -Djdk.attach.allowAttachSelf
+ *    GetPackageBootLoaderChildLayer
+ * @summary Exercise Class.getPackage on a class defined to the boot loader
+ *    but in a module that is in a child layer rather than the boot layer
+ */
+
+import com.sun.tools.attach.VirtualMachine;
+
+public class GetPackageBootLoaderChildLayer {
+    public static void main(String[] args) throws Exception {
+        // ensure that the java.management module is not in the boot layer
+        ModuleLayer.boot().findModule("java.management").ifPresent(m -> {
+            throw new RuntimeException("java.management loaded!!!");
+        });
+
+        // start local JMX agent via the attach mechanism
+        String vmid = "" + ProcessHandle.current().pid();
+        VirtualMachine vm = VirtualMachine.attach(vmid);
+        vm.startLocalManagementAgent();
+
+        // check layer, class loader, and Package object
+        Class<?> clazz = Class.forName("javax.management.MXBean");
+        if (clazz.getModule().getLayer() == ModuleLayer.boot())
+            throw new RuntimeException("Module is in boot layer!!!");
+        ClassLoader loader = clazz.getClassLoader();
+        if (loader != null)
+            throw new RuntimeException("Unexpected class loader: " + loader);
+        Package p = clazz.getPackage();
+        if (!p.getName().equals("javax.management"))
+            throw new RuntimeException("Unexpected package " + p);
+    }
+}