| /* |
| * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. |
| * Copyright (c) 2018 SAP SE. 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 |
| * @summary Test messages of IllegalAccessError. |
| * @modules java.base/java.lang:open |
| * java.base/jdk.internal.org.objectweb.asm |
| * @compile IAE_Loader1.java IAE_Loader2.java IAE78_A.java IAE78_B.java |
| * IllegalAccessErrorTest.java |
| * @run main/othervm -Xbootclasspath/a:. test.IllegalAccessErrorTest |
| */ |
| |
| // Put this test into a package so we see qualified class names in |
| // the error messages. Verify that classes are printed with '.' instead |
| // of '/'. |
| package test; |
| |
| import java.lang.reflect.*; |
| import java.lang.invoke.MethodHandles.Lookup; |
| import static java.lang.invoke.MethodHandles.*; |
| import static java.lang.invoke.MethodHandles.Lookup.*; |
| import java.security.*; |
| |
| import jdk.internal.org.objectweb.asm.ClassWriter; |
| import jdk.internal.org.objectweb.asm.MethodVisitor; |
| import static jdk.internal.org.objectweb.asm.Opcodes.*; |
| |
| import test.*; |
| |
| abstract public class IllegalAccessErrorTest { |
| |
| // interface |
| private static String expectedErrorMessage1a_1 = |
| "class test.IAE1_B cannot access its superinterface test.IAE1_A " + |
| "(test.IAE1_B is in unnamed module of loader test.IAE_Loader1 @"; |
| private static String expectedErrorMessage1a_2 = |
| "; test.IAE1_A is in unnamed module of loader 'app')"; |
| private static String expectedErrorMessage1b_1 = |
| "class test.IAE1_B cannot access its superinterface test.IAE1_A " + |
| "(test.IAE1_B is in unnamed module of loader 'someCLName1' @"; |
| private static String expectedErrorMessage1b_2 = |
| "; test.IAE1_A is in unnamed module of loader 'app')"; |
| |
| // abstract class |
| private static String expectedErrorMessage2_1 = |
| "class test.IAE2_B cannot access its abstract superclass test.IAE2_A " + |
| "(test.IAE2_B is in unnamed module of loader 'someCLName2' @"; |
| private static String expectedErrorMessage2_2 = |
| "; test.IAE2_A is in unnamed module of loader 'app')"; |
| |
| // class |
| private static String expectedErrorMessage3_1 = |
| "class test.IAE3_B cannot access its superclass test.IAE3_A " + |
| "(test.IAE3_B is in unnamed module of loader 'someCLName3' @"; |
| private static String expectedErrorMessage3_2 = |
| "; test.IAE3_A is in unnamed module of loader 'app')"; |
| |
| public static void test123(String loaderName, |
| String expectedErrorMessage_1, |
| String expectedErrorMessage_2, |
| String testClass) throws Exception { |
| String[] classNames = { testClass }; |
| // Some classes under a new Loader. |
| ClassLoader l = new IAE_Loader1(loaderName, classNames); |
| |
| try { |
| l.loadClass(testClass); |
| throw new RuntimeException("Expected IllegalAccessError was not thrown."); |
| } catch (IllegalAccessError iae) { |
| String errorMsg = iae.getMessage(); |
| if (!(errorMsg.contains(expectedErrorMessage_1) && |
| errorMsg.contains(expectedErrorMessage_2))) { |
| System.out.println("Expected: " + expectedErrorMessage_1 + "@id " + expectedErrorMessage_2 +"\n" + |
| "but got: " + errorMsg); |
| throw new RuntimeException("Wrong error message of IllegalAccessError."); |
| } else { |
| System.out.println("Passed with message: " + errorMsg); |
| } |
| } |
| } |
| |
| // Generate a class file with the given class name. The class implements Runnable |
| // with a run method to invokestatic the given targetClass/targetMethod. |
| static byte[] iae4_generateRunner(String className, |
| String targetClass, |
| String targetMethod) throws Exception { |
| |
| ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS |
| + ClassWriter.COMPUTE_FRAMES); |
| cw.visit(V9, |
| ACC_PUBLIC + ACC_SUPER, |
| className.replace(".", "/"), |
| null, |
| "java/lang/Object", |
| new String[] { "java/lang/Runnable" }); |
| |
| // <init> |
| MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); |
| mv.visitVarInsn(ALOAD, 0); |
| mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false); |
| mv.visitInsn(RETURN); |
| mv.visitMaxs(0, 0); |
| mv.visitEnd(); |
| |
| // run() |
| String tc = targetClass.replace(".", "/"); |
| mv = cw.visitMethod(ACC_PUBLIC, "run", "()V", null, null); |
| mv.visitMethodInsn(INVOKESTATIC, tc, targetMethod, "()V", false); |
| mv.visitInsn(RETURN); |
| mv.visitMaxs(0, 0); |
| mv.visitEnd(); |
| |
| cw.visitEnd(); |
| return cw.toByteArray(); |
| } |
| |
| // Private method that should raise IllegalAccessError when called. |
| private static void iae4_m() { } |
| |
| private static String expectedErrorMessage4 = |
| "class test.Runner4 tried to access private method 'void test.IllegalAccessErrorTest.iae4_m()' " + |
| "(test.Runner4 and test.IllegalAccessErrorTest are in unnamed module of loader 'app')"; |
| |
| // Test according to java/lang/invoke/DefineClassTest.java |
| public static void test4_privateMethod() throws Exception { |
| final String THIS_PACKAGE = IllegalAccessErrorTest.class.getPackageName(); |
| final String THIS_CLASS = IllegalAccessErrorTest.class.getName(); |
| final String CLASS_NAME = THIS_PACKAGE + ".Runner4"; |
| Lookup lookup = lookup(); |
| |
| // private |
| byte[] classBytes = iae4_generateRunner(CLASS_NAME, THIS_CLASS, "iae4_m"); |
| Class<?> clazz = lookup.defineClass(classBytes); |
| Runnable r = (Runnable) clazz.getDeclaredConstructor().newInstance(); |
| try { |
| r.run(); |
| throw new RuntimeException("Expected IllegalAccessError was not thrown."); |
| } catch (IllegalAccessError exc) { |
| String errorMsg = exc.getMessage(); |
| if (!errorMsg.equals(expectedErrorMessage4)) { |
| System.out.println("Expected: " + expectedErrorMessage4 + "\n" + |
| "but got: " + errorMsg); |
| throw new RuntimeException("Wrong error message of IllegalAccessError."); |
| } |
| System.out.println("Passed with message: " + errorMsg); |
| } |
| } |
| |
| // Generate a class file with the given class name. The class implements Runnable |
| // with a run method to invokestatic the given targetClass/targetField. |
| static byte[] iae5_generateRunner(String className, |
| String targetClass, |
| String targetField) throws Exception { |
| |
| ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS |
| + ClassWriter.COMPUTE_FRAMES); |
| cw.visit(V9, |
| ACC_PUBLIC + ACC_SUPER, |
| className.replace(".", "/"), |
| null, |
| "java/lang/Object", |
| new String[] { "java/lang/Runnable" }); |
| |
| // <init> |
| MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); |
| mv.visitVarInsn(ALOAD, 0); |
| mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false); |
| mv.visitInsn(RETURN); |
| mv.visitMaxs(0, 0); |
| mv.visitEnd(); |
| |
| // run() |
| String tc = targetClass.replace(".", "/"); |
| mv = cw.visitMethod(ACC_PUBLIC, "run", "()V", null, null); |
| mv.visitFieldInsn(GETSTATIC, tc, targetField, "I"); |
| mv.visitInsn(RETURN); |
| mv.visitMaxs(0, 0); |
| mv.visitEnd(); |
| |
| cw.visitEnd(); |
| return cw.toByteArray(); |
| } |
| |
| // Private field that should raise IllegalAccessError when accessed. |
| private static int iae5_f = 77; |
| |
| private static String expectedErrorMessage5 = |
| "class test.Runner5 tried to access private field test.IllegalAccessErrorTest.iae5_f " + |
| "(test.Runner5 and test.IllegalAccessErrorTest are in unnamed module of loader 'app')"; |
| |
| // Test according to java/lang/invoke/DefineClassTest.java |
| public static void test5_privateField() throws Exception { |
| final String THIS_PACKAGE = IllegalAccessErrorTest.class.getPackageName(); |
| final String THIS_CLASS = IllegalAccessErrorTest.class.getName(); |
| final String CLASS_NAME = THIS_PACKAGE + ".Runner5"; |
| Lookup lookup = lookup(); |
| |
| // private |
| byte[] classBytes = iae5_generateRunner(CLASS_NAME, THIS_CLASS, "iae5_f"); |
| Class<?> clazz = lookup.defineClass(classBytes); |
| Runnable r = (Runnable) clazz.getDeclaredConstructor().newInstance(); |
| try { |
| r.run(); |
| throw new RuntimeException("Expected IllegalAccessError was not thrown."); |
| } catch (IllegalAccessError exc) { |
| String errorMsg = exc.getMessage(); |
| if (!errorMsg.equals(expectedErrorMessage5)) { |
| System.out.println("Expected: " + expectedErrorMessage5 + "\n" + |
| "but got: " + errorMsg); |
| throw new RuntimeException("Wrong error message of IllegalAccessError."); |
| } |
| System.out.println("Passed with message: " + errorMsg); |
| } |
| } |
| |
| private static String expectedErrorMessage6 = |
| "failed to access class test.IAE6_A from class test.IAE6_B " + |
| "(test.IAE6_A is in unnamed module of loader 'app'; test.IAE6_B is in unnamed module of loader 'test6_class_CL' @"; |
| |
| public static void test6_class() throws Exception { |
| ClassLoader base = IllegalAccessErrorTest.class.getClassLoader(); |
| IAE_Loader2 loader = new IAE_Loader2("test6_class_CL", base.getParent(), base, new String[0], |
| new String[] { IAE6_A.class.getName() }); |
| Class<?> cl = loader.loadClass(IAE6_B.class.getName()); |
| Method m = cl.getDeclaredMethod("create", new Class[0]); |
| m.setAccessible(true); |
| |
| try { |
| m.invoke(null, new Object[0]); |
| throw new RuntimeException("Expected IllegalAccessError was not thrown."); |
| } catch (InvocationTargetException e) { |
| IllegalAccessError iae = (IllegalAccessError) e.getCause(); |
| String errorMsg = iae.getMessage(); |
| if (!errorMsg.contains(expectedErrorMessage6)) { |
| System.out.println("Expected: " + expectedErrorMessage6 + "id)\n" + |
| "but got: " + errorMsg); |
| throw new RuntimeException("Wrong error message of IllegalAccessError."); |
| } |
| System.out.println("Passed with message: " + errorMsg); |
| } |
| } |
| |
| private static String expectedErrorMessage7_1 = |
| "class test.IAE78_B tried to access method 'void test.IAE78_A.<init>()' " + |
| "(test.IAE78_B is in unnamed module of loader 'test7_method_CL' @"; |
| private static String expectedErrorMessage7_2 = |
| "; test.IAE78_A is in unnamed module of loader 'app')"; |
| |
| // Similar to test4. |
| public static void test7_method() throws Exception { |
| ClassLoader base = IllegalAccessErrorTest.class.getClassLoader(); |
| IAE_Loader2 loader = new IAE_Loader2("test7_method_CL", base.getParent(), base, new String[0], |
| new String[] {IAE78_A.class.getName()}); |
| Class<?> cl = loader.loadClass(IAE78_B.class.getName()); |
| Method m = cl.getDeclaredMethod("create", new Class[0]); |
| |
| try { |
| m.invoke(null, new Object[0]); |
| } catch (InvocationTargetException e) { |
| IllegalAccessError iae = (IllegalAccessError) e.getCause(); |
| String errorMsg = iae.getMessage(); |
| if (!(errorMsg.contains(expectedErrorMessage7_1) && |
| errorMsg.contains(expectedErrorMessage7_2))) { |
| System.out.println("Expected: " + expectedErrorMessage7_1 + "id" + expectedErrorMessage7_2 + "\n" + |
| "but got: " + errorMsg); |
| throw new RuntimeException("Wrong error message of IllegalAccessError."); |
| } |
| System.out.println("Passed with message: " + errorMsg); |
| } |
| } |
| |
| private static String expectedErrorMessage8_1 = |
| "class test.IAE78_B tried to access field test.IAE78_A.f " + |
| "(test.IAE78_B is in unnamed module of loader 'test8_field_CL' @"; |
| private static String expectedErrorMessage8_2 = |
| "; test.IAE78_A is in unnamed module of loader 'app')"; |
| |
| // Similar to test5. |
| public static void test8_field() throws Exception { |
| ClassLoader base = IllegalAccessErrorTest.class.getClassLoader(); |
| IAE_Loader2 loader = new IAE_Loader2("test8_field_CL", base.getParent(), base, new String[0], |
| new String[] { IAE78_A.class.getName() }); |
| Class<?> cl = loader.loadClass(IAE78_B.class.getName()); |
| Method m = cl.getDeclaredMethod("access", new Class[0]); |
| |
| try { |
| m.invoke(null, new Object[0]); |
| } |
| catch (InvocationTargetException e) { |
| IllegalAccessError iae = (IllegalAccessError) e.getCause(); |
| String errorMsg = iae.getMessage(); |
| if (!(errorMsg.contains(expectedErrorMessage8_1) && |
| errorMsg.contains(expectedErrorMessage8_2))) { |
| System.out.println("Expected: " + expectedErrorMessage8_1 + "id" + expectedErrorMessage8_2 + "\n" + |
| "but got: " + errorMsg); |
| throw new RuntimeException("Wrong error message of IllegalAccessError."); |
| } |
| System.out.println("Passed with message: " + errorMsg); |
| } |
| } |
| |
| public static void main(String[] args) throws Exception { |
| test123(null, expectedErrorMessage1a_1, expectedErrorMessage1a_2, "test.IAE1_B"); // interface |
| test123("someCLName1", expectedErrorMessage1b_1, expectedErrorMessage1b_2, "test.IAE1_B"); // interface |
| test123("someCLName2", expectedErrorMessage2_1, expectedErrorMessage2_2, "test.IAE2_B"); // abstract class |
| test123("someCLName3", expectedErrorMessage3_1, expectedErrorMessage3_2, "test.IAE3_B"); // class |
| test4_privateMethod(); |
| test5_privateField(); |
| test6_class(); |
| test7_method(); |
| test8_field(); |
| } |
| } |
| |
| // Class hierarchies for test1. |
| interface IAE1_A { |
| public IAE1_D gen(); |
| } |
| |
| class IAE1_B implements IAE1_A { |
| public IAE1_D gen() { |
| return null; |
| } |
| } |
| |
| abstract class IAE1_C { |
| } |
| |
| class IAE1_D extends IAE1_C { |
| } |
| |
| |
| // Class hierarchies for test2. |
| abstract class IAE2_A { |
| abstract public IAE2_D gen(); |
| } |
| |
| class IAE2_B extends IAE2_A { |
| public IAE2_D gen() { |
| return null; |
| } |
| } |
| |
| abstract class IAE2_C { |
| } |
| |
| class IAE2_D extends IAE2_C { |
| } |
| |
| |
| // Class hierarchies for test3. |
| class IAE3_A { |
| public IAE3_D gen() { |
| return null; |
| }; |
| } |
| |
| class IAE3_B extends IAE3_A { |
| public IAE3_D gen() { |
| return null; |
| } |
| } |
| |
| abstract class IAE3_C { |
| } |
| |
| class IAE3_D extends IAE3_C { |
| } |
| |
| |
| // Class hierarchies for test6. |
| class IAE6_A { |
| IAE6_A() { |
| // Nothing to do. |
| } |
| } |
| |
| class IAE6_B { |
| public static void create() { |
| new IAE6_A(); |
| } |
| } |