/* * 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 = "class test.IAE1_B cannot access its superinterface test.IAE1_A"; private static String expectedErrorMessage1b = "class someCLName1//test.IAE1_B cannot access its superinterface test.IAE1_A"; // abstract class private static String expectedErrorMessage2 = "class someCLName2//test.IAE2_B cannot access its abstract superclass test.IAE2_A"; // class private static String expectedErrorMessage3 = "class someCLName3//test.IAE3_B cannot access its superclass test.IAE3_A"; public static void test123(String loaderName, String expectedErrorMessage, 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.equals(expectedErrorMessage)) { System.out.println("Expected: " + expectedErrorMessage + "\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 = "tried to access private method test.IllegalAccessErrorTest.iae4_m()V from class test.Runner4"; // 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 = "tried to access private field test.IllegalAccessErrorTest.iae5_f from class test.Runner5"; // 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 test6_class_CL//test.IAE6_B"; 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.equals(expectedErrorMessage6)) { System.out.println("Expected: " + expectedErrorMessage6 + "\n" + "but got: " + errorMsg); throw new RuntimeException("Wrong error message of IllegalAccessError."); } System.out.println("Passed with message: " + errorMsg); } } private static String expectedErrorMessage7 = "tried to access method test.IAE78_A.()V from class test7_method_CL//test.IAE78_B"; // 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.equals(expectedErrorMessage7)) { System.out.println("Expected: " + expectedErrorMessage7 + "\n" + "but got: " + errorMsg); throw new RuntimeException("Wrong error message of IllegalAccessError."); } System.out.println("Passed with message: " + errorMsg); } } private static String expectedErrorMessage8 = "tried to access field test.IAE78_A.f from class test8_field_CL//test.IAE78_B"; // 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.equals(expectedErrorMessage8)) { System.out.println("Expected: " + expectedErrorMessage8 + "\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, "test.IAE1_B"); // interface test123("someCLName1", expectedErrorMessage1b, "test.IAE1_B"); // interface test123("someCLName2", expectedErrorMessage2, "test.IAE2_B"); // abstract class test123("someCLName3", expectedErrorMessage3, "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(); } }