1 /* 2 * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 /* 26 * @test Do not cache classes that are loaded from a fake location. 27 * @bug 8352001 28 * @requires vm.cds.supports.aot.class.linking 29 * @comment work around JDK-8345635 30 * @requires !vm.jvmci.enabled 31 * @library /test/jdk/lib/testlibrary /test/lib 32 * @build FakeCodeLocation 33 * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar FakeCodeLocationApp 34 * @run driver jdk.test.lib.helpers.ClassFileInstaller ClassNotInJar1 ClassNotInJar2 35 * @run driver FakeCodeLocation 36 */ 37 38 import java.lang.invoke.MethodHandles; 39 import java.lang.reflect.InaccessibleObjectException; 40 import java.lang.reflect.Method; 41 import java.nio.file.Files; 42 import java.nio.file.Paths; 43 import java.security.ProtectionDomain; 44 45 import jdk.test.lib.cds.CDSAppTester; 46 import jdk.test.lib.helpers.ClassFileInstaller; 47 import jdk.test.lib.process.OutputAnalyzer; 48 import jdk.test.lib.StringArrayUtils; 49 50 public class FakeCodeLocation { 51 static final String appJar = "app.jar"; 52 static final String mainClass = FakeCodeLocationApp.class.getName(); 53 54 public static void main(String[] args) throws Exception { 55 (new Tester(false)).run(new String[] {"STATIC"}); 56 (new Tester(true )).run(new String[] {"STATIC"}); 57 (new Tester(false)).run(new String[] {"AOT"}); 58 (new Tester(true )).run(new String[] {"AOT"}); 59 } 60 61 static class Tester extends CDSAppTester { 62 boolean addOpen;; 63 public Tester(boolean addOpen) { 64 super(mainClass); 65 this.addOpen = addOpen; 66 } 67 68 @Override 69 public String classpath(RunMode runMode) { 70 return appJar; 71 } 72 73 @Override 74 public String[] vmArgs(RunMode runMode) { 75 String[] args = new String[] { 76 "-Xlog:cds", 77 "-Xlog:cds+class=debug", 78 "-Xlog:class+load", 79 }; 80 if (addOpen) { 81 args = StringArrayUtils.concat(args, "--add-opens", "java.base/java.lang=ALL-UNNAMED", "-XX:-AOTClassLinking"); 82 } 83 return args; 84 } 85 86 @Override 87 public String[] appCommandLine(RunMode runMode) { 88 return new String[] { 89 mainClass, 90 addOpen ? "hasAddedOpen" : "hasNotAddedOpen", 91 }; 92 } 93 94 @Override 95 public void checkExecution(OutputAnalyzer out, RunMode runMode) throws Exception { 96 if (isDumping(runMode)) { 97 out.shouldMatch("cds,class.* FakeCodeLocationApp"); 98 out.shouldNotMatch("cds,class.* ClassNotInJar1"); 99 out.shouldNotMatch("cds,class.* ClassNotInJar2"); 100 } 101 102 if (runMode.isProductionRun()) { 103 out.shouldMatch("class,load.* FakeCodeLocationApp .*source: shared objects file"); 104 out.shouldNotMatch("class,load.* ClassNotInJar1 .*source: shared objects file"); 105 out.shouldNotMatch("class,load.* ClassNotInJar2 .*source: shared objects file"); 106 } 107 } 108 } 109 } 110 111 class FakeCodeLocationApp { 112 static boolean hasAddedOpen; 113 114 public static void main(String args[]) throws Exception { 115 hasAddedOpen = args[0].equals("hasAddedOpen"); 116 testWithLookup(); 117 testWithSetAccessible(); 118 } 119 120 // Define a class using Lookup.defineClass(). The ClassFileParser should see "__JVM_DefineClass__" 121 // as the source location, so this class will be excluded, as the location is not supported. 122 static void testWithLookup() throws Exception { 123 byte[] data = Files.readAllBytes(Paths.get("ClassNotInJar1.class")); 124 Class c = MethodHandles.lookup().defineClass(data); 125 System.out.println(c.getProtectionDomain()); 126 System.out.println(c.getProtectionDomain().getCodeSource()); 127 } 128 129 // Use setAccessible to call into ClassLoader.defineClass(). In this case, the ClassFileParser 130 // sees "app.jar" as the source location, but the app.jar doesn't contain this class file, so we 131 // should exclude this class. 132 static void testWithSetAccessible() throws Exception { 133 Method m = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class, ProtectionDomain.class); 134 System.out.println(m); 135 try { 136 m.setAccessible(true); 137 if (!hasAddedOpen) { 138 throw new RuntimeException("setAccessible() should have failed because '--add-opens java.base/java.lang=ALL-UNNAMED' was not specified"); 139 } 140 } catch (InaccessibleObjectException t) { 141 if (hasAddedOpen) { 142 throw new RuntimeException("setAccessible() failed even though '--add-opens java.base/java.lang=ALL-UNNAMED' was specified"); 143 } else { 144 System.out.println("\n\nExpected: " + t); 145 t.printStackTrace(System.out); 146 return; 147 } 148 } 149 150 ProtectionDomain pd = FakeCodeLocationApp.class.getProtectionDomain(); 151 ClassLoader appLoader = FakeCodeLocationApp.class.getClassLoader(); 152 byte[] data = Files.readAllBytes(Paths.get("ClassNotInJar2.class")); 153 Class c = null; 154 try { 155 c = (Class)m.invoke(appLoader, "ClassNotInJar2", data, 0, data.length, pd); 156 } catch (Throwable t) { 157 System.out.println(t); 158 t.printStackTrace(System.out); 159 return; 160 } 161 162 System.out.println(c); 163 System.out.println(c.getProtectionDomain()); 164 System.out.println(c.getProtectionDomain().getCodeSource()); 165 } 166 } 167 168 class ClassNotInJar1 {} 169 170 class ClassNotInJar2 {}