/* * 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" }); // MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()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" }); // MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()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.()' " + "(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(); } }