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
--- 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) {
+ }
+ }
+}