1 /* 2 * Copyright (c) 2023, 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 In Leyden repo, classes that are linked during the assembly phase can 27 * skip verification constraint checks. See JDK-8317269. 28 * NOTE: this feature is not included when JDK-8315737 is upstreamed to the mainline. 29 * @requires vm.cds 30 * @requires vm.cds.supports.aot.class.linking 31 * @summary Test for verification of classes that are aot-linked 32 * @library /test/jdk/lib/testlibrary 33 * /test/lib 34 * /test/hotspot/jtreg/runtime/cds/appcds 35 * /test/hotspot/jtreg/runtime/cds/appcds/test-classes 36 * @build GoodOldClass BadOldClass BadOldClass2 BadNewClass BadNewClass2 37 * @build AOTClassLinkingVerification 38 * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar WhiteBox.jar jdk.test.whitebox.WhiteBox 39 * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app1.jar 40 * AOTClassLinkingVerificationApp 41 * Unlinked UnlinkedSuper 42 * BadOldClass 43 * BadOldClass2 44 * BadNewClass 45 * BadNewClass2 46 * GoodOldClass Vehicle Car 47 * Util 48 * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app2.jar 49 * UnlinkedSub 50 * Foo NotFoo 51 * @run driver AOTClassLinkingVerification 52 */ 53 54 import java.io.File; 55 import java.lang.invoke.MethodHandles; 56 import jdk.test.lib.helpers.ClassFileInstaller; 57 import jdk.test.whitebox.WhiteBox; 58 59 public class AOTClassLinkingVerification { 60 static final String app1Jar = ClassFileInstaller.getJarPath("app1.jar"); 61 static final String app2Jar = ClassFileInstaller.getJarPath("app2.jar"); 62 static final String wbJar = TestCommon.getTestJar("WhiteBox.jar"); 63 static final String bootAppendWhiteBox = "-Xbootclasspath/a:" + wbJar; 64 static final String mainClass = AOTClassLinkingVerificationApp.class.getName(); 65 66 public static void main(String[] args) throws Exception { 67 // Dump without app2.jar so: 68 // - Unlinked can be resolved, but UnlinkedSuper UnlinkedSub cannot be resolved, 69 // so Unlinked cannot be verified at dump time. 70 // - BadOldClass2 can be resolved, but Foo and NotFoo cannot be resolved, 71 // so BadOldClass2 cannot be verified at dump time. 72 // - BadNewClass2 can be resolved, but Foo and NotFoo cannot be resolved, 73 // so BadNewClass2 cannot be verified at dump time. 74 TestCommon.testDump(app1Jar, TestCommon.list("Unlinked", 75 "BadOldClass", 76 "BadOldClass2", 77 "BadNewClass", 78 "BadNewClass2", 79 "GoodOldClass"), 80 bootAppendWhiteBox, 81 "-XX:+AOTClassLinking", 82 "-XX:+ArchivePackages", 83 "-XX:+ArchiveProtectionDomains", 84 "-Xlog:cds+class=debug"); 85 86 TestCommon.run("-cp", app1Jar + File.pathSeparator + app2Jar, 87 "-XX:+UnlockDiagnosticVMOptions", 88 "-XX:+WhiteBoxAPI", 89 bootAppendWhiteBox, 90 "AOTClassLinkingVerificationApp", app1Jar) 91 .assertNormalExit(); 92 } 93 } 94 95 class AOTClassLinkingVerificationApp { 96 static WhiteBox wb = WhiteBox.getWhiteBox(); 97 static ClassLoader classLoader = AOTClassLinkingVerificationApp.class.getClassLoader(); 98 static File app1Jar; 99 100 public static void main(String[] args) throws Exception { 101 app1Jar = new File(args[0]); 102 assertNotShared(UnlinkedSub.class); 103 assertShared(UnlinkedSuper.class); 104 assertNotShared(Unlinked.class); // failed verification during dump time 105 assertNotShared(Foo.class); 106 assertNotShared(NotFoo.class); 107 String s = Unlinked.doit(); 108 if (!s.equals("heyhey")) { 109 throw new RuntimeException("Unlinked.doit() returns wrong result: " + s); 110 } 111 112 Class cls_BadOldClass = Class.forName("BadOldClass", false, classLoader); 113 assertNotShared(cls_BadOldClass); // failed verification during dump time 114 try { 115 cls_BadOldClass.newInstance(); 116 throw new RuntimeException("BadOldClass cannot be verified"); 117 } catch (VerifyError expected) {} 118 119 Class cls_BadOldClass2 = Class.forName("BadOldClass2", false, classLoader); 120 assertNotShared(cls_BadOldClass2); // failed verification during dump time 121 try { 122 cls_BadOldClass2.newInstance(); 123 throw new RuntimeException("BadOldClass2 cannot be verified"); 124 } catch (VerifyError expected) {} 125 126 Class cls_BadNewClass = Class.forName("BadNewClass", false, classLoader); 127 assertNotShared(cls_BadNewClass); // failed verification during dump time 128 try { 129 cls_BadNewClass.newInstance(); 130 throw new RuntimeException("BadNewClass cannot be verified"); 131 } catch (VerifyError expected) {} 132 133 Class cls_BadNewClass2 = Class.forName("BadNewClass2", false, classLoader); 134 assertNotShared(cls_BadNewClass2); // failed verification during dump time 135 try { 136 cls_BadNewClass2.newInstance(); 137 throw new RuntimeException("BadNewClass2 cannot be verified"); 138 } catch (VerifyError expected) {} 139 140 141 // Although Vehicle and Car are not specified in the classlist, they are archived as 142 // they were used during dumptime verification of GoodOldClass 143 assertAlreadyLoaded("Vehicle"); 144 assertAlreadyLoaded("Car"); 145 assertAlreadyLoaded("GoodOldClass"); 146 147 assertShared(GoodOldClass.class); 148 assertShared(Vehicle.class); 149 assertShared(Car.class); 150 151 GoodOldClass.doit(); // Should not fail 152 } 153 154 static void assertShared(Class c) { 155 if (!wb.isSharedClass(c)) { 156 throw new RuntimeException("wb.isSharedClass(" + c.getName() + ") should be true"); 157 } 158 } 159 160 static void assertNotShared(Class c) { 161 if (wb.isSharedClass(c)) { 162 throw new RuntimeException("wb.isSharedClass(" + c.getName() + ") should be false"); 163 } 164 } 165 166 static void assertAlreadyLoaded(String className) throws Exception { 167 byte[] data = Util.getClassFileFromJar(app1Jar, className); 168 try { 169 MethodHandles.lookup().defineClass(data); 170 } catch (LinkageError e) { 171 if (e.getMessage().contains("duplicate class definition for " + className)) { 172 return; 173 } else { 174 throw e; 175 } 176 } 177 throw new RuntimeException(className + " must have already been loaded"); 178 } 179 } 180 181 182 class Unlinked { 183 static String doit() { 184 UnlinkedSuper sup = new UnlinkedSub(); 185 return sup.doit(); 186 } 187 } 188 189 abstract class UnlinkedSuper { 190 abstract String doit(); 191 } 192 193 class UnlinkedSub extends UnlinkedSuper { 194 String doit() { 195 return "heyhey"; 196 } 197 } 198 199 class Foo {} 200 class NotFoo {} 201 202 class Vehicle {} 203 class Car extends Vehicle {}