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_1 =
  57         "class test.IAE1_B cannot access its superinterface test.IAE1_A " +
  58         "(test.IAE1_B is in unnamed module of loader test.IAE_Loader1 @";
  59     private static String expectedErrorMessage1a_2 =
  60         "; test.IAE1_A is in unnamed module of loader 'app')";
  61     private static String expectedErrorMessage1b_1 =
  62         "class test.IAE1_B cannot access its superinterface test.IAE1_A " +
  63         "(test.IAE1_B is in unnamed module of loader 'someCLName1' @";
  64     private static String expectedErrorMessage1b_2 =
  65         "; test.IAE1_A is in unnamed module of loader 'app')";
  66 
  67     // abstract class
  68     private static String expectedErrorMessage2_1 =
  69         "class test.IAE2_B cannot access its abstract superclass test.IAE2_A " +
  70         "(test.IAE2_B is in unnamed module of loader 'someCLName2' @";
  71     private static String expectedErrorMessage2_2 =
  72         "; test.IAE2_A is in unnamed module of loader 'app')";
  73 
  74     // class
  75     private static String expectedErrorMessage3_1 =
  76         "class test.IAE3_B cannot access its superclass test.IAE3_A " +
  77         "(test.IAE3_B is in unnamed module of loader 'someCLName3' @";
  78     private static String expectedErrorMessage3_2 =
  79         "; test.IAE3_A is in unnamed module of loader 'app')";
  80 
  81     public static void test123(String loaderName,
  82                                String expectedErrorMessage_1,
  83                                String expectedErrorMessage_2,
  84                                String testClass) throws Exception {
  85         String[] classNames = { testClass };
  86         // Some classes under a new Loader.
  87         ClassLoader l = new IAE_Loader1(loaderName, classNames);
  88 
  89         try {
  90             l.loadClass(testClass);
  91             throw new RuntimeException("Expected IllegalAccessError was not thrown.");
  92         } catch (IllegalAccessError iae) {
  93             String errorMsg = iae.getMessage();
  94             if (!(errorMsg.contains(expectedErrorMessage_1) &&
  95                   errorMsg.contains(expectedErrorMessage_2))) {
  96                 System.out.println("Expected: " + expectedErrorMessage_1 + "@id " + expectedErrorMessage_2 +"\n" +
  97                                    "but got:  " + errorMsg);
  98                 throw new RuntimeException("Wrong error message of IllegalAccessError.");
  99             } else {
 100                 System.out.println("Passed with message: " + errorMsg);
 101             }
 102         }
 103     }
 104 
 105     // Generate a class file with the given class name. The class implements Runnable
 106     // with a run method to invokestatic the given targetClass/targetMethod.
 107     static byte[] iae4_generateRunner(String className,
 108                                       String targetClass,
 109                                       String targetMethod) throws Exception {
 110 
 111         ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS
 112                                          + ClassWriter.COMPUTE_FRAMES);
 113         cw.visit(V9,
 114                 ACC_PUBLIC + ACC_SUPER,
 115                 className.replace(".", "/"),
 116                 null,
 117                 "java/lang/Object",
 118                 new String[] { "java/lang/Runnable" });
 119 
 120         // <init>
 121         MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
 122         mv.visitVarInsn(ALOAD, 0);
 123         mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
 124         mv.visitInsn(RETURN);
 125         mv.visitMaxs(0, 0);
 126         mv.visitEnd();
 127 
 128         // run()
 129         String tc = targetClass.replace(".", "/");
 130         mv = cw.visitMethod(ACC_PUBLIC, "run", "()V", null, null);
 131         mv.visitMethodInsn(INVOKESTATIC, tc, targetMethod, "()V", false);
 132         mv.visitInsn(RETURN);
 133         mv.visitMaxs(0, 0);
 134         mv.visitEnd();
 135 
 136         cw.visitEnd();
 137         return cw.toByteArray();
 138     }
 139 
 140     // Private method that should raise IllegalAccessError when called.
 141     private static void iae4_m() { }
 142 
 143     private static String expectedErrorMessage4 =
 144         "class test.Runner4 tried to access private method 'void test.IllegalAccessErrorTest.iae4_m()' " +
 145         "(test.Runner4 and test.IllegalAccessErrorTest are in unnamed module of loader 'app')";
 146 
 147     // Test according to java/lang/invoke/DefineClassTest.java
 148     public static void test4_privateMethod() throws Exception {
 149         final String THIS_PACKAGE = IllegalAccessErrorTest.class.getPackageName();
 150         final String THIS_CLASS   = IllegalAccessErrorTest.class.getName();
 151         final String CLASS_NAME   = THIS_PACKAGE + ".Runner4";
 152         Lookup lookup = lookup();
 153 
 154         // private
 155         byte[] classBytes = iae4_generateRunner(CLASS_NAME, THIS_CLASS, "iae4_m");
 156         Class<?> clazz = lookup.defineClass(classBytes);
 157         Runnable r = (Runnable) clazz.getDeclaredConstructor().newInstance();
 158         try {
 159             r.run();
 160             throw new RuntimeException("Expected IllegalAccessError was not thrown.");
 161         } catch (IllegalAccessError exc) {
 162             String errorMsg = exc.getMessage();
 163             if (!errorMsg.equals(expectedErrorMessage4)) {
 164                 System.out.println("Expected: " + expectedErrorMessage4 + "\n" +
 165                                    "but got:  " + errorMsg);
 166                 throw new RuntimeException("Wrong error message of IllegalAccessError.");
 167             }
 168             System.out.println("Passed with message: " + errorMsg);
 169         }
 170     }
 171 
 172     // Generate a class file with the given class name. The class implements Runnable
 173     // with a run method to invokestatic the given targetClass/targetField.
 174     static byte[] iae5_generateRunner(String className,
 175                                       String targetClass,
 176                                       String targetField) throws Exception {
 177 
 178         ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS
 179                                          + ClassWriter.COMPUTE_FRAMES);
 180         cw.visit(V9,
 181                  ACC_PUBLIC + ACC_SUPER,
 182                  className.replace(".", "/"),
 183                  null,
 184                  "java/lang/Object",
 185                  new String[] { "java/lang/Runnable" });
 186 
 187         // <init>
 188         MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
 189         mv.visitVarInsn(ALOAD, 0);
 190         mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
 191         mv.visitInsn(RETURN);
 192         mv.visitMaxs(0, 0);
 193         mv.visitEnd();
 194 
 195         // run()
 196         String tc = targetClass.replace(".", "/");
 197         mv = cw.visitMethod(ACC_PUBLIC, "run", "()V", null, null);
 198         mv.visitFieldInsn(GETSTATIC, tc, targetField, "I");
 199         mv.visitInsn(RETURN);
 200         mv.visitMaxs(0, 0);
 201         mv.visitEnd();
 202 
 203         cw.visitEnd();
 204         return cw.toByteArray();
 205     }
 206 
 207     // Private field that should raise IllegalAccessError when accessed.
 208     private static int iae5_f = 77;
 209 
 210     private static String expectedErrorMessage5 =
 211         "class test.Runner5 tried to access private field test.IllegalAccessErrorTest.iae5_f " +
 212         "(test.Runner5 and test.IllegalAccessErrorTest are in unnamed module of loader 'app')";
 213 
 214     // Test according to java/lang/invoke/DefineClassTest.java
 215     public static void test5_privateField() throws Exception {
 216         final String THIS_PACKAGE = IllegalAccessErrorTest.class.getPackageName();
 217         final String THIS_CLASS   = IllegalAccessErrorTest.class.getName();
 218         final String CLASS_NAME   = THIS_PACKAGE + ".Runner5";
 219         Lookup lookup = lookup();
 220 
 221         // private
 222         byte[] classBytes = iae5_generateRunner(CLASS_NAME, THIS_CLASS, "iae5_f");
 223         Class<?> clazz = lookup.defineClass(classBytes);
 224         Runnable r = (Runnable) clazz.getDeclaredConstructor().newInstance();
 225         try {
 226             r.run();
 227             throw new RuntimeException("Expected IllegalAccessError was not thrown.");
 228         } catch (IllegalAccessError exc) {
 229             String errorMsg = exc.getMessage();
 230             if (!errorMsg.equals(expectedErrorMessage5)) {
 231                 System.out.println("Expected: " + expectedErrorMessage5 + "\n" +
 232                                    "but got:  " + errorMsg);
 233                 throw new RuntimeException("Wrong error message of IllegalAccessError.");
 234             }
 235             System.out.println("Passed with message: " + errorMsg);
 236         }
 237     }
 238 
 239     private static String expectedErrorMessage6 =
 240         "failed to access class test.IAE6_A from class test.IAE6_B " +
 241         "(test.IAE6_A is in unnamed module of loader 'app'; test.IAE6_B is in unnamed module of loader 'test6_class_CL' @";
 242 
 243     public static void test6_class() throws Exception {
 244         ClassLoader base = IllegalAccessErrorTest.class.getClassLoader();
 245         IAE_Loader2 loader = new IAE_Loader2("test6_class_CL", base.getParent(), base, new String[0],
 246                 new String[] { IAE6_A.class.getName() });
 247         Class<?> cl = loader.loadClass(IAE6_B.class.getName());
 248         Method m = cl.getDeclaredMethod("create", new Class[0]);
 249         m.setAccessible(true);
 250 
 251         try {
 252             m.invoke(null, new Object[0]);
 253             throw new RuntimeException("Expected IllegalAccessError was not thrown.");
 254         } catch (InvocationTargetException e) {
 255             IllegalAccessError iae = (IllegalAccessError) e.getCause();
 256             String errorMsg = iae.getMessage();
 257             if (!errorMsg.contains(expectedErrorMessage6)) {
 258                 System.out.println("Expected: " + expectedErrorMessage6 + "id)\n" +
 259                                    "but got:  " + errorMsg);
 260                 throw new RuntimeException("Wrong error message of IllegalAccessError.");
 261             }
 262             System.out.println("Passed with message: " + errorMsg);
 263         }
 264     }
 265 
 266     private static String expectedErrorMessage7_1 =
 267         "class test.IAE78_B tried to access method 'void test.IAE78_A.<init>()' " +
 268         "(test.IAE78_B is in unnamed module of loader 'test7_method_CL' @";
 269     private static String expectedErrorMessage7_2 =
 270         "; test.IAE78_A is in unnamed module of loader 'app')";
 271 
 272     // Similar to test4.
 273     public static void test7_method() throws Exception {
 274         ClassLoader base = IllegalAccessErrorTest.class.getClassLoader();
 275         IAE_Loader2 loader = new IAE_Loader2("test7_method_CL", base.getParent(), base, new String[0],
 276                 new String[] {IAE78_A.class.getName()});
 277         Class<?> cl = loader.loadClass(IAE78_B.class.getName());
 278         Method m = cl.getDeclaredMethod("create", new Class[0]);
 279 
 280         try {
 281             m.invoke(null, new Object[0]);
 282         } catch (InvocationTargetException e) {
 283             IllegalAccessError iae = (IllegalAccessError) e.getCause();
 284             String errorMsg = iae.getMessage();
 285             if (!(errorMsg.contains(expectedErrorMessage7_1) &&
 286                   errorMsg.contains(expectedErrorMessage7_2))) {
 287                 System.out.println("Expected: " + expectedErrorMessage7_1 + "id" + expectedErrorMessage7_2 + "\n" +
 288                                    "but got:  " + errorMsg);
 289                 throw new RuntimeException("Wrong error message of IllegalAccessError.");
 290             }
 291             System.out.println("Passed with message: " + errorMsg);
 292         }
 293     }
 294 
 295     private static String expectedErrorMessage8_1 =
 296         "class test.IAE78_B tried to access field test.IAE78_A.f " +
 297         "(test.IAE78_B is in unnamed module of loader 'test8_field_CL' @";
 298     private static String expectedErrorMessage8_2 =
 299         "; test.IAE78_A is in unnamed module of loader 'app')";
 300 
 301     // Similar to test5.
 302     public static void test8_field() throws Exception {
 303         ClassLoader base = IllegalAccessErrorTest.class.getClassLoader();
 304         IAE_Loader2 loader = new IAE_Loader2("test8_field_CL", base.getParent(), base, new String[0],
 305                                              new String[] { IAE78_A.class.getName() });
 306         Class<?> cl = loader.loadClass(IAE78_B.class.getName());
 307         Method m = cl.getDeclaredMethod("access", new Class[0]);
 308 
 309         try {
 310             m.invoke(null, new Object[0]);
 311         }
 312         catch (InvocationTargetException e) {
 313             IllegalAccessError iae = (IllegalAccessError) e.getCause();
 314             String errorMsg = iae.getMessage();
 315             if (!(errorMsg.contains(expectedErrorMessage8_1) &&
 316                   errorMsg.contains(expectedErrorMessage8_2))) {
 317                 System.out.println("Expected: " + expectedErrorMessage8_1 + "id" + expectedErrorMessage8_2 + "\n" +
 318                                    "but got:  " + errorMsg);
 319                 throw new RuntimeException("Wrong error message of IllegalAccessError.");
 320             }
 321             System.out.println("Passed with message: " + errorMsg);
 322         }
 323     }
 324 
 325     public static void main(String[] args) throws Exception {
 326         test123(null,          expectedErrorMessage1a_1, expectedErrorMessage1a_2, "test.IAE1_B"); // interface
 327         test123("someCLName1", expectedErrorMessage1b_1, expectedErrorMessage1b_2, "test.IAE1_B"); // interface
 328         test123("someCLName2", expectedErrorMessage2_1,  expectedErrorMessage2_2,  "test.IAE2_B"); // abstract class
 329         test123("someCLName3", expectedErrorMessage3_1,  expectedErrorMessage3_2,  "test.IAE3_B"); // class
 330         test4_privateMethod();
 331         test5_privateField();
 332         test6_class();
 333         test7_method();
 334         test8_field();
 335     }
 336 }
 337 
 338 // Class hierarchies for test1.
 339 interface IAE1_A {
 340     public IAE1_D gen();
 341 }
 342 
 343 class IAE1_B implements IAE1_A {
 344     public IAE1_D gen() {
 345         return null;
 346     }
 347 }
 348 
 349 abstract class IAE1_C {
 350 }
 351 
 352 class IAE1_D extends IAE1_C {
 353 }
 354 
 355 
 356 // Class hierarchies for test2.
 357 abstract class IAE2_A {
 358     abstract public IAE2_D gen();
 359 }
 360 
 361 class IAE2_B extends IAE2_A {
 362     public IAE2_D gen() {
 363         return null;
 364     }
 365 }
 366 
 367 abstract class IAE2_C {
 368 }
 369 
 370 class IAE2_D extends IAE2_C {
 371 }
 372 
 373 
 374 // Class hierarchies for test3.
 375 class IAE3_A {
 376     public IAE3_D gen() {
 377         return null;
 378     };
 379 }
 380 
 381 class IAE3_B extends IAE3_A {
 382     public IAE3_D gen() {
 383         return null;
 384     }
 385 }
 386 
 387 abstract class IAE3_C {
 388 }
 389 
 390 class IAE3_D extends IAE3_C {
 391 }
 392 
 393 
 394 // Class hierarchies for test6.
 395 class IAE6_A {
 396     IAE6_A() {
 397         // Nothing to do.
 398     }
 399 }
 400 
 401 class IAE6_B {
 402     public static void create() {
 403         new IAE6_A();
 404     }
 405 }