1 /* 2 * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. 3 * Copyright (c) 2018 SAP SE. All rights reserved. 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * This code is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 only, as 8 * published by the Free Software Foundation. 9 * 10 * This code is distributed in the hope that it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 * version 2 for more details (a copy is included in the LICENSE file that 14 * accompanied this code). 15 * 16 * You should have received a copy of the GNU General Public License version 17 * 2 along with this work; if not, write to the Free Software Foundation, 18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 19 * 20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 21 * or visit www.oracle.com if you need additional information or have any 22 * questions. 23 * 24 */ 25 26 /** 27 * @test 28 * @summary Test messages of IllegalAccessError. 29 * @modules java.base/java.lang:open 30 * java.base/jdk.internal.org.objectweb.asm 31 * @compile IAE_Loader1.java IAE_Loader2.java IAE78_A.java IAE78_B.java 32 * IllegalAccessErrorTest.java 33 * @run main/othervm -Xbootclasspath/a:. test.IllegalAccessErrorTest 34 */ 35 36 // Put this test into a package so we see qualified class names in 37 // the error messages. Verify that classes are printed with '.' instead 38 // of '/'. 39 package test; 40 41 import java.lang.reflect.*; 42 import java.lang.invoke.MethodHandles.Lookup; 43 import static java.lang.invoke.MethodHandles.*; 44 import static java.lang.invoke.MethodHandles.Lookup.*; 45 import java.security.*; 46 47 import jdk.internal.org.objectweb.asm.ClassWriter; 48 import jdk.internal.org.objectweb.asm.MethodVisitor; 49 import static jdk.internal.org.objectweb.asm.Opcodes.*; 50 51 import test.*; 52 53 abstract public class IllegalAccessErrorTest { 54 55 // interface 56 private static String expectedErrorMessage1a = 57 "class test.IAE1_B cannot access its superinterface test.IAE1_A"; 58 private static String expectedErrorMessage1b = 59 "class someCLName1//test.IAE1_B cannot access its superinterface test.IAE1_A"; 60 61 // abstract class 62 private static String expectedErrorMessage2 = 63 "class someCLName2//test.IAE2_B cannot access its abstract superclass test.IAE2_A"; 64 65 // class 66 private static String expectedErrorMessage3 = 67 "class someCLName3//test.IAE3_B cannot access its superclass test.IAE3_A"; 68 69 public static void test123(String loaderName, 70 String expectedErrorMessage, 71 String testClass) throws Exception { 72 String[] classNames = { testClass }; 73 // Some classes under a new Loader. 74 ClassLoader l = new IAE_Loader1(loaderName, classNames); 75 76 try { 77 l.loadClass(testClass); 78 throw new RuntimeException("Expected IllegalAccessError was not thrown."); 79 } catch (IllegalAccessError iae) { 80 String errorMsg = iae.getMessage(); 81 if (!errorMsg.equals(expectedErrorMessage)) { 82 System.out.println("Expected: " + expectedErrorMessage + "\n" + 83 "but got: " + errorMsg); 84 throw new RuntimeException("Wrong error message of IllegalAccessError."); 85 } else { 86 System.out.println("Passed with message: " + errorMsg); 87 } 88 } 89 } 90 91 // Generate a class file with the given class name. The class implements Runnable 92 // with a run method to invokestatic the given targetClass/targetMethod. 93 static byte[] iae4_generateRunner(String className, 94 String targetClass, 95 String targetMethod) throws Exception { 96 97 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS 98 + ClassWriter.COMPUTE_FRAMES); 99 cw.visit(V9, 100 ACC_PUBLIC + ACC_SUPER, 101 className.replace(".", "/"), 102 null, 103 "java/lang/Object", 104 new String[] { "java/lang/Runnable" }); 105 106 // <init> 107 MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); 108 mv.visitVarInsn(ALOAD, 0); 109 mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false); 110 mv.visitInsn(RETURN); 111 mv.visitMaxs(0, 0); 112 mv.visitEnd(); 113 114 // run() 115 String tc = targetClass.replace(".", "/"); 116 mv = cw.visitMethod(ACC_PUBLIC, "run", "()V", null, null); 117 mv.visitMethodInsn(INVOKESTATIC, tc, targetMethod, "()V", false); 118 mv.visitInsn(RETURN); 119 mv.visitMaxs(0, 0); 120 mv.visitEnd(); 121 122 cw.visitEnd(); 123 return cw.toByteArray(); 124 } 125 126 // Private method that should raise IllegalAccessError when called. 127 private static void iae4_m() { } 128 129 private static String expectedErrorMessage4 = 130 "tried to access private method test.IllegalAccessErrorTest.iae4_m()V from class test.Runner4"; 131 132 // Test according to java/lang/invoke/DefineClassTest.java 133 public static void test4_privateMethod() throws Exception { 134 final String THIS_PACKAGE = IllegalAccessErrorTest.class.getPackageName(); 135 final String THIS_CLASS = IllegalAccessErrorTest.class.getName(); 136 final String CLASS_NAME = THIS_PACKAGE + ".Runner4"; 137 Lookup lookup = lookup(); 138 139 // private 140 byte[] classBytes = iae4_generateRunner(CLASS_NAME, THIS_CLASS, "iae4_m"); 141 Class<?> clazz = lookup.defineClass(classBytes); 142 Runnable r = (Runnable) clazz.getDeclaredConstructor().newInstance(); 143 try { 144 r.run(); 145 throw new RuntimeException("Expected IllegalAccessError was not thrown."); 146 } catch (IllegalAccessError exc) { 147 String errorMsg = exc.getMessage(); 148 if (!errorMsg.equals(expectedErrorMessage4)) { 149 System.out.println("Expected: " + expectedErrorMessage4 + "\n" + 150 "but got: " + errorMsg); 151 throw new RuntimeException("Wrong error message of IllegalAccessError."); 152 } 153 System.out.println("Passed with message: " + errorMsg); 154 } 155 } 156 157 // Generate a class file with the given class name. The class implements Runnable 158 // with a run method to invokestatic the given targetClass/targetField. 159 static byte[] iae5_generateRunner(String className, 160 String targetClass, 161 String targetField) throws Exception { 162 163 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS 164 + ClassWriter.COMPUTE_FRAMES); 165 cw.visit(V9, 166 ACC_PUBLIC + ACC_SUPER, 167 className.replace(".", "/"), 168 null, 169 "java/lang/Object", 170 new String[] { "java/lang/Runnable" }); 171 172 // <init> 173 MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); 174 mv.visitVarInsn(ALOAD, 0); 175 mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false); 176 mv.visitInsn(RETURN); 177 mv.visitMaxs(0, 0); 178 mv.visitEnd(); 179 180 // run() 181 String tc = targetClass.replace(".", "/"); 182 mv = cw.visitMethod(ACC_PUBLIC, "run", "()V", null, null); 183 mv.visitFieldInsn(GETSTATIC, tc, targetField, "I"); 184 mv.visitInsn(RETURN); 185 mv.visitMaxs(0, 0); 186 mv.visitEnd(); 187 188 cw.visitEnd(); 189 return cw.toByteArray(); 190 } 191 192 // Private field that should raise IllegalAccessError when accessed. 193 private static int iae5_f = 77; 194 195 private static String expectedErrorMessage5 = 196 "tried to access private field test.IllegalAccessErrorTest.iae5_f from class test.Runner5"; 197 198 // Test according to java/lang/invoke/DefineClassTest.java 199 public static void test5_privateField() throws Exception { 200 final String THIS_PACKAGE = IllegalAccessErrorTest.class.getPackageName(); 201 final String THIS_CLASS = IllegalAccessErrorTest.class.getName(); 202 final String CLASS_NAME = THIS_PACKAGE + ".Runner5"; 203 Lookup lookup = lookup(); 204 205 // private 206 byte[] classBytes = iae5_generateRunner(CLASS_NAME, THIS_CLASS, "iae5_f"); 207 Class<?> clazz = lookup.defineClass(classBytes); 208 Runnable r = (Runnable) clazz.getDeclaredConstructor().newInstance(); 209 try { 210 r.run(); 211 throw new RuntimeException("Expected IllegalAccessError was not thrown."); 212 } catch (IllegalAccessError exc) { 213 String errorMsg = exc.getMessage(); 214 if (!errorMsg.equals(expectedErrorMessage5)) { 215 System.out.println("Expected: " + expectedErrorMessage5 + "\n" + 216 "but got: " + errorMsg); 217 throw new RuntimeException("Wrong error message of IllegalAccessError."); 218 } 219 System.out.println("Passed with message: " + errorMsg); 220 } 221 } 222 223 private static String expectedErrorMessage6 = 224 "failed to access class test.IAE6_A from class test6_class_CL//test.IAE6_B"; 225 226 public static void test6_class() throws Exception { 227 ClassLoader base = IllegalAccessErrorTest.class.getClassLoader(); 228 IAE_Loader2 loader = new IAE_Loader2("test6_class_CL", base.getParent(), base, new String[0], 229 new String[] { IAE6_A.class.getName() }); 230 Class<?> cl = loader.loadClass(IAE6_B.class.getName()); 231 Method m = cl.getDeclaredMethod("create", new Class[0]); 232 m.setAccessible(true); 233 234 try { 235 m.invoke(null, new Object[0]); 236 throw new RuntimeException("Expected IllegalAccessError was not thrown."); 237 } catch (InvocationTargetException e) { 238 IllegalAccessError iae = (IllegalAccessError) e.getCause(); 239 String errorMsg = iae.getMessage(); 240 if (!errorMsg.equals(expectedErrorMessage6)) { 241 System.out.println("Expected: " + expectedErrorMessage6 + "\n" + 242 "but got: " + errorMsg); 243 throw new RuntimeException("Wrong error message of IllegalAccessError."); 244 } 245 System.out.println("Passed with message: " + errorMsg); 246 } 247 } 248 249 private static String expectedErrorMessage7 = 250 "tried to access method test.IAE78_A.<init>()V from class test7_method_CL//test.IAE78_B"; 251 252 // Similar to test4. 253 public static void test7_method() throws Exception { 254 ClassLoader base = IllegalAccessErrorTest.class.getClassLoader(); 255 IAE_Loader2 loader = new IAE_Loader2("test7_method_CL", base.getParent(), base, new String[0], 256 new String[] {IAE78_A.class.getName()}); 257 Class<?> cl = loader.loadClass(IAE78_B.class.getName()); 258 Method m = cl.getDeclaredMethod("create", new Class[0]); 259 260 try { 261 m.invoke(null, new Object[0]); 262 } catch (InvocationTargetException e) { 263 IllegalAccessError iae = (IllegalAccessError) e.getCause(); 264 String errorMsg = iae.getMessage(); 265 if (!errorMsg.equals(expectedErrorMessage7)) { 266 System.out.println("Expected: " + expectedErrorMessage7 + "\n" + 267 "but got: " + errorMsg); 268 throw new RuntimeException("Wrong error message of IllegalAccessError."); 269 } 270 System.out.println("Passed with message: " + errorMsg); 271 } 272 } 273 274 private static String expectedErrorMessage8 = 275 "tried to access field test.IAE78_A.f from class test8_field_CL//test.IAE78_B"; 276 277 // Similar to test5. 278 public static void test8_field() throws Exception { 279 ClassLoader base = IllegalAccessErrorTest.class.getClassLoader(); 280 IAE_Loader2 loader = new IAE_Loader2("test8_field_CL", base.getParent(), base, new String[0], 281 new String[] { IAE78_A.class.getName() }); 282 Class<?> cl = loader.loadClass(IAE78_B.class.getName()); 283 Method m = cl.getDeclaredMethod("access", new Class[0]); 284 285 try { 286 m.invoke(null, new Object[0]); 287 } 288 catch (InvocationTargetException e) { 289 IllegalAccessError iae = (IllegalAccessError) e.getCause(); 290 String errorMsg = iae.getMessage(); 291 if (!errorMsg.equals(expectedErrorMessage8)) { 292 System.out.println("Expected: " + expectedErrorMessage8 + "\n" + 293 "but got: " + errorMsg); 294 throw new RuntimeException("Wrong error message of IllegalAccessError."); 295 } 296 System.out.println("Passed with message: " + errorMsg); 297 } 298 } 299 300 public static void main(String[] args) throws Exception { 301 test123(null, expectedErrorMessage1a, "test.IAE1_B"); // interface 302 test123("someCLName1", expectedErrorMessage1b, "test.IAE1_B"); // interface 303 test123("someCLName2", expectedErrorMessage2, "test.IAE2_B"); // abstract class 304 test123("someCLName3", expectedErrorMessage3, "test.IAE3_B"); // class 305 test4_privateMethod(); 306 test5_privateField(); 307 test6_class(); 308 test7_method(); 309 test8_field(); 310 } 311 } 312 313 // Class hierarchies for test1. 314 interface IAE1_A { 315 public IAE1_D gen(); 316 } 317 318 class IAE1_B implements IAE1_A { 319 public IAE1_D gen() { 320 return null; 321 } 322 } 323 324 abstract class IAE1_C { 325 } 326 327 class IAE1_D extends IAE1_C { 328 } 329 330 331 // Class hierarchies for test2. 332 abstract class IAE2_A { 333 abstract public IAE2_D gen(); 334 } 335 336 class IAE2_B extends IAE2_A { 337 public IAE2_D gen() { 338 return null; 339 } 340 } 341 342 abstract class IAE2_C { 343 } 344 345 class IAE2_D extends IAE2_C { 346 } 347 348 349 // Class hierarchies for test3. 350 class IAE3_A { 351 public IAE3_D gen() { 352 return null; 353 }; 354 } 355 356 class IAE3_B extends IAE3_A { 357 public IAE3_D gen() { 358 return null; 359 } 360 } 361 362 abstract class IAE3_C { 363 } 364 365 class IAE3_D extends IAE3_C { 366 } 367 368 369 // Class hierarchies for test6. 370 class IAE6_A { 371 IAE6_A() { 372 // Nothing to do. 373 } 374 } 375 376 class IAE6_B { 377 public static void create() { 378 new IAE6_A(); 379 } 380 }