Skip to content

Commit bbec3c0

Browse files
committed
8354558: -XX:AOTMode=record crashes with boot loader package-info class
Reviewed-by: ccheung, matsaave
1 parent b10a304 commit bbec3c0

File tree

4 files changed

+114
-14
lines changed

4 files changed

+114
-14
lines changed

src/hotspot/share/classfile/classLoader.cpp

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1219,6 +1219,7 @@ void ClassLoader::record_result(JavaThread* current, InstanceKlass* ik,
12191219
// must be valid since the class has been successfully parsed.
12201220
const char* path = ClassLoader::uri_to_path(src);
12211221
assert(path != nullptr, "sanity");
1222+
bool found_invalid = false;
12221223
AOTClassLocationConfig::dumptime_iterate([&] (AOTClassLocation* cl) {
12231224
int i = cl->index();
12241225
// for index 0 and the stream->source() is the modules image or has the jrt: protocol.
@@ -1242,10 +1243,15 @@ void ClassLoader::record_result(JavaThread* current, InstanceKlass* ik,
12421243
classpath_index = i;
12431244
} else {
12441245
if (cl->from_boot_classpath()) {
1245-
// The class must be from boot loader append path which consists of
1246-
// -Xbootclasspath/a and jvmti appended entries.
1247-
assert(loader == nullptr, "sanity");
1248-
classpath_index = i;
1246+
if (loader != nullptr) {
1247+
// Probably loaded by jdk/internal/loader/ClassLoaders$BootClassLoader. Don't archive
1248+
// such classes.
1249+
ik->set_shared_classpath_index(-1);
1250+
ik->set_shared_class_loader_type(ClassLoader::BOOT_LOADER);
1251+
found_invalid = true;
1252+
} else {
1253+
classpath_index = i;
1254+
}
12491255
}
12501256
}
12511257
} else {
@@ -1256,13 +1262,17 @@ void ClassLoader::record_result(JavaThread* current, InstanceKlass* ik,
12561262
}
12571263
}
12581264
}
1259-
if (classpath_index >= 0) {
1265+
if (classpath_index >= 0 || found_invalid) {
12601266
return false; // quit iterating
12611267
} else {
12621268
return true; // Keep iterating
12631269
}
12641270
});
12651271

1272+
if (found_invalid) {
1273+
return;
1274+
}
1275+
12661276
// No path entry found for this class: most likely a shared class loaded by the
12671277
// user defined classloader.
12681278
if (classpath_index < 0 && !SystemDictionaryShared::is_builtin_loader(ik->class_loader_data())) {
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
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
27+
* @summary AOT cache handling for package-info class loaded by jdk/internal/loader/ClassLoaders$BootClassLoader
28+
* @bug 8354558
29+
* @requires vm.cds.supports.aot.class.linking
30+
* @comment work around JDK-8345635
31+
* @requires !vm.jvmci.enabled
32+
* @library /test/lib /test/jdk/java/lang/Package/bootclasspath/boot
33+
* @build PackageInfoClass foo.Foo foo.MyAnnotation foo.package-info
34+
* @run driver jdk.test.lib.helpers.ClassFileInstaller -jar boot.jar foo.Foo foo.package-info foo.MyAnnotation
35+
* @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar PackageInfoClassApp
36+
* @run driver PackageInfoClass AOT
37+
*/
38+
39+
import java.lang.annotation.Annotation;
40+
import java.util.Arrays;
41+
import jdk.test.lib.cds.CDSAppTester.RunMode;
42+
import jdk.test.lib.cds.SimpleCDSAppTester;
43+
import jdk.test.lib.process.OutputAnalyzer;
44+
45+
public class PackageInfoClass {
46+
public static void main(String... args) throws Exception {
47+
SimpleCDSAppTester.of("PackageInfoClass")
48+
.classpath("app.jar")
49+
.addVmArgs("-Xbootclasspath/a:boot.jar")
50+
.appCommandLine("PackageInfoClassApp")
51+
.setAssemblyChecker((OutputAnalyzer out, RunMode runMode) -> {
52+
if (runMode == RunMode.TRAINING) {
53+
out.shouldContain("Skipping foo/package-info: Unsupported location");
54+
}
55+
})
56+
.runAOTWorkflow();
57+
}
58+
}
59+
60+
class PackageInfoClassApp {
61+
public static void main(String[] args) throws Exception {
62+
// This code is taken from test/jdk/java/lang/Package/bootclasspath/GetPackageFromBootClassPath.java
63+
Class<?> c = Class.forName("foo.Foo", false, null);
64+
Package p = c.getPackage();
65+
Annotation[] annotations = p.getAnnotations();
66+
Class<?> annType = Class.forName("foo.MyAnnotation", false, null);
67+
if (annotations.length != 1 ||
68+
annotations[0].annotationType() != annType) {
69+
throw new RuntimeException("Expected foo.MyAnnotation but got " +
70+
Arrays.toString(annotations));
71+
}
72+
}
73+
}

test/lib/jdk/test/lib/cds/CDSAppTester.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ private enum Workflow {
8686
}
8787

8888
public enum RunMode {
89-
TRAINING, // -XX:DumpLoadedClassList OR {-XX:AOTMode=create -XX:AOTConfiguration}
89+
TRAINING, // -XX:DumpLoadedClassList OR {-XX:AOTMode=record -XX:AOTConfiguration}
9090
DUMP_STATIC, // -Xshare:dump
9191
DUMP_DYNAMIC, // -XX:ArchiveClassesArExit
9292
ASSEMBLY, // JEP 483 (assembly phase, app logic not executed)

test/lib/jdk/test/lib/cds/SimpleCDSAppTester.java

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,13 @@
2424
package jdk.test.lib.cds;
2525

2626
import java.io.File;
27+
import java.util.function.BiConsumer;
28+
import java.util.function.Consumer;
29+
30+
import jdk.test.lib.cds.CDSAppTester.RunMode;
2731
import jdk.test.lib.process.OutputAnalyzer;
2832
import jdk.test.lib.StringArrayUtils;
2933

30-
import java.util.function.Consumer;
31-
3234
/*
3335
* A simpler way to use CDSAppTester. Example:
3436
*
@@ -49,8 +51,8 @@
4951
*/
5052
public class SimpleCDSAppTester {
5153
private String name;
52-
private Consumer<OutputAnalyzer> assemblyChecker;
53-
private Consumer<OutputAnalyzer> productionChecker;
54+
private BiConsumer<OutputAnalyzer, RunMode> assemblyChecker;
55+
private BiConsumer<OutputAnalyzer, RunMode> productionChecker;
5456
private String classpath;
5557
private String modulepath;
5658
private String[] appCommandLine;
@@ -98,16 +100,31 @@ public SimpleCDSAppTester appCommandLine(String... args) {
98100
return this;
99101
}
100102

101-
public SimpleCDSAppTester setAssemblyChecker(Consumer<OutputAnalyzer> checker) {
103+
public SimpleCDSAppTester setAssemblyChecker(BiConsumer<OutputAnalyzer, RunMode> checker) {
102104
this.assemblyChecker = checker;
103105
return this;
104106
}
105107

106-
public SimpleCDSAppTester setProductionChecker(Consumer<OutputAnalyzer> checker) {
108+
public SimpleCDSAppTester setProductionChecker(BiConsumer<OutputAnalyzer, RunMode> checker) {
107109
this.productionChecker = checker;
108110
return this;
109111
}
110112

113+
114+
public SimpleCDSAppTester setAssemblyChecker(Consumer<OutputAnalyzer> checker) {
115+
this.assemblyChecker = (OutputAnalyzer out, RunMode runMode) -> {
116+
checker.accept(out);
117+
};
118+
return this;
119+
}
120+
121+
public SimpleCDSAppTester setProductionChecker(Consumer<OutputAnalyzer> checker) {
122+
this.productionChecker = (OutputAnalyzer out, RunMode runMode) -> {
123+
checker.accept(out);
124+
};
125+
return this;
126+
}
127+
111128
class Tester extends CDSAppTester {
112129
public Tester(String name) {
113130
super(name);
@@ -137,11 +154,11 @@ public String[] appCommandLine(RunMode runMode) {
137154
public void checkExecution(OutputAnalyzer out, RunMode runMode) throws Exception {
138155
if (isDumping(runMode) && runMode != RunMode.TRAINING) {
139156
if (assemblyChecker != null) {
140-
assemblyChecker.accept(out);
157+
assemblyChecker.accept(out, runMode);
141158
}
142159
} else if (runMode.isProductionRun()) {
143160
if (productionChecker != null) {
144-
productionChecker.accept(out);
161+
productionChecker.accept(out, runMode);
145162
}
146163
}
147164
}

0 commit comments

Comments
 (0)