8058575: IllegalAccessError trying to access package-private class from VM anonymous class
authorhseigel
Wed, 07 Sep 2016 07:21:43 -0400
changeset 40964 c4a7c6d1cfb3
parent 40963 c7c990c4ec68
child 40966 d1d7b21e1abd
8058575: IllegalAccessError trying to access package-private class from VM anonymous class Summary: Put anonymous classes in unnamed package into host class's package. Throw exception if host class's package differs from anonymous class. Reviewed-by: coleenp, acorn
jdk/src/java.base/share/classes/jdk/internal/misc/Unsafe.java
jdk/test/java/lang/Class/GetModuleTest.java
jdk/test/java/lang/invoke/VMAnonymousClass.java
jdk/test/jdk/internal/misc/Unsafe/TestBadHostClass.java
--- a/jdk/src/java.base/share/classes/jdk/internal/misc/Unsafe.java	Wed Sep 07 03:35:45 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/misc/Unsafe.java	Wed Sep 07 07:21:43 2016 -0400
@@ -1197,6 +1197,9 @@
         if (hostClass == null || data == null) {
             throw new NullPointerException();
         }
+        if (hostClass.isArray() || hostClass.isPrimitive()) {
+            throw new IllegalArgumentException();
+        }
 
         return defineAnonymousClass0(hostClass, data, cpPatches);
     }
--- a/jdk/test/java/lang/Class/GetModuleTest.java	Wed Sep 07 03:35:45 2016 +0000
+++ b/jdk/test/java/lang/Class/GetModuleTest.java	Wed Sep 07 07:21:43 2016 -0400
@@ -101,11 +101,8 @@
         return new Object[][] {
 
             { GetModuleTest.class,      null },
-            { GetModuleTest[].class,    null },
             { Object.class,             null },
-            { Object[].class,           null },
             { Component.class,          null },
-            { Component[].class,        null },
 
         };
     }
@@ -117,7 +114,7 @@
     public void testGetModuleOnVMAnonymousClass(Class<?> hostClass, String ignore) {
 
         // choose a class name in the same package as the host class
-        String prefix = packageName(hostClass);
+        String prefix = hostClass.getPackageName();
         if (prefix.length() > 0)
             prefix = prefix.replace('.', '/') + "/";
         String className = prefix + "Anon";
@@ -136,17 +133,6 @@
         assertTrue(anonClass.getModule() == hostClass.getModule());
     }
 
-    private static String packageName(Class<?> c) {
-        if (c.isArray()) {
-            return packageName(c.getComponentType());
-        } else {
-            String name = c.getName();
-            int dot = name.lastIndexOf('.');
-            if (dot == -1) return "";
-            return name.substring(0, dot);
-        }
-    }
-
     private static int constantPoolSize(byte[] classFile) {
         return ((classFile[8] & 0xFF) << 8) | (classFile[9] & 0xFF);
     }
--- a/jdk/test/java/lang/invoke/VMAnonymousClass.java	Wed Sep 07 03:35:45 2016 +0000
+++ b/jdk/test/java/lang/invoke/VMAnonymousClass.java	Wed Sep 07 07:21:43 2016 -0400
@@ -57,9 +57,9 @@
     @Test public void testJavaLangInvoke()  throws Throwable { test("java/lang/invoke");  }
     @Test public void testProhibitedJavaPkg() throws Throwable {
        try {
-          test("java/prohibited");
-       } catch (SecurityException e) {
-         return;
+           test("java/prohibited");
+       } catch (IllegalArgumentException e) {
+           return;
        }
        throw new RuntimeException("Expected SecurityException");
      }
@@ -72,10 +72,17 @@
         if (pkg.equals("java/prohibited")) {
             VMAnonymousClass sampleclass = new VMAnonymousClass();
             host_class = (Class)sampleclass.getClass();
+        } else if (pkg.equals("java/lang")) {
+          host_class = Object.class;
+        } else if (pkg.equals("java/util")) {
+            host_class = java.util.ArrayList.class;
+        } else if (pkg.equals("jdk/internal/misc")) {
+            host_class = jdk.internal.misc.Signal.class;
+        } else if (pkg.equals("java/lang/invoke")) {
+            host_class = java.lang.invoke.CallSite.class;
         } else {
-            host_class = Object.class;
+            throw new RuntimeException("Unexpected pkg: " + pkg);
         }
-
         // Define VM anonymous class
         Class anonClass = unsafe.defineAnonymousClass(host_class, bytes, null);
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/internal/misc/Unsafe/TestBadHostClass.java	Wed Sep 07 07:21:43 2016 -0400
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2016, 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
+ * @bug 8058575
+ * @summary Test that bad host classes cause exceptions to get thrown.
+ * @library /test/lib
+ * @modules java.base/jdk.internal.misc
+ *          java.base/jdk.internal.org.objectweb.asm
+ * @run main TestBadHostClass
+ */
+
+
+import java.lang.*;
+import java.lang.reflect.Field;
+import jdk.internal.misc.Unsafe;
+import jdk.test.lib.unsafe.UnsafeHelper;
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import static jdk.internal.org.objectweb.asm.Opcodes.*;
+
+// Test that bad host classes cause exceptions.
+public class TestBadHostClass {
+
+    private static final Unsafe unsafe = Unsafe.getUnsafe();
+
+    private static String packageName(Class<?> c) {
+        if (c.isArray()) {
+            return packageName(c.getComponentType());
+        } else {
+            String name = c.getName();
+            int dot = name.lastIndexOf('.');
+            if (dot == -1) return "";
+            return name.substring(0, dot);
+        }
+    }
+
+    private static int constantPoolSize(byte[] classFile) {
+        return ((classFile[8] & 0xFF) << 8) | (classFile[9] & 0xFF);
+    }
+
+    static public void badHostClass(Class<?> hostClass) {
+        // choose a class name in the same package as the host class
+        String className;
+        if (hostClass != null) {
+            String prefix = packageName(hostClass);
+            if (prefix.length() > 0)
+                prefix = prefix.replace('.', '/') + "/";
+            className = prefix + "Anon";
+        } else {
+           className = "Anon";
+        }
+
+        // create the class
+        String superName = "java/lang/Object";
+        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS
+                                         + ClassWriter.COMPUTE_FRAMES);
+        cw.visit(V1_8, ACC_PUBLIC + ACC_FINAL + ACC_SUPER,
+                 className, null, superName, null);
+        byte[] classBytes = cw.toByteArray();
+        int cpPoolSize = constantPoolSize(classBytes);
+        Class<?> anonClass
+            = unsafe.defineAnonymousClass(hostClass, classBytes, new Object[cpPoolSize]);
+    }
+
+    public static void main(String args[]) throws Exception {
+        // host class is an array of java.lang.Objects.
+        try {
+            badHostClass(Object[].class);
+        } catch (IllegalArgumentException ex) {
+        }
+
+        // host class is an array of objects of this class.
+        try {
+            badHostClass(TestBadHostClass[].class);
+        } catch (IllegalArgumentException ex) {
+        }
+
+        // host class is null.
+        try {
+            badHostClass(null);
+        } catch (NullPointerException ex) {
+        }
+
+        // host class is a primitive array class.
+        try {
+            badHostClass(int[].class);
+        } catch (IllegalArgumentException ex) {
+        }
+    }
+}