1 /*
2 * Copyright (c) 2026, 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 Ensure archived nullable flat field and static null-restricted field metadata are validated when the field class is substituted.
28 * @bug 8382584
29 * @requires vm.cds
30 * @library /test/lib
31 * @enablePreview
32 * @modules java.base/jdk.internal.vm.annotation
33 * @compile ArchivedFieldMetadataMismatchTest.java
34 * @run driver jdk.test.lib.helpers.StrictProcessor ArchivedFieldMetadataInstanceHolder
35 * @run main/othervm ArchivedFieldMetadataMismatchTest
36 */
37
38 import java.io.File;
39 import java.lang.invoke.MethodHandles;
40 import jdk.test.lib.helpers.ClassFileInstaller;
41 import java.nio.file.Files;
42 import java.nio.file.Path;
43
44 import jdk.internal.vm.annotation.LooselyConsistentValue;
45 import jdk.internal.vm.annotation.NullRestricted;
46 import jdk.test.lib.helpers.StrictInit;
47 import jdk.test.lib.process.OutputAnalyzer;
48
49 public class ArchivedFieldMetadataMismatchTest {
50 static final String[] appClasses = {
51 "ArchivedFieldMetadataInstanceApp",
52 "ArchivedFieldMetadataInstancePoint",
53 "ArchivedFieldMetadataInstanceHolder",
54 "ArchivedFieldMetadataStaticApp",
55 "ArchivedFieldMetadataStaticPoint",
56 "ArchivedFieldMetadataStaticHolder",
57 };
58 static String appJar;
59
60 public static void main(String[] args) throws Exception {
61 appJar = ClassFileInstaller.writeJar("app.jar", appClasses);
62 testInstanceField();
63 testStaticField();
64 }
65
66 private static void testInstanceField() throws Exception {
67 String pointClassFile = new File(System.getProperty("test.classes", "."),
68 "ArchivedFieldMetadataInstancePoint.class").getPath();
69
70 TestCommon.checkDump(TestCommon.dump(appJar,
71 appClasses,
72 "--enable-preview",
73 "-XX:+UnlockDiagnosticVMOptions",
74 "-XX:+UseNullableNonAtomicValueFlattening"));
75
76 OutputAnalyzer output = TestCommon.exec(appJar,
77 "--enable-preview",
78 "-Xlog:class+load,class+preload",
79 "-XX:+UnlockDiagnosticVMOptions",
80 "-XX:+UseNullableNonAtomicValueFlattening",
81 "ArchivedFieldMetadataInstanceApp", pointClassFile);
82 TestCommon.checkExec(output);
83
84 output.shouldContain("Preloading of class ArchivedFieldMetadataInstancePoint during loading of shared class " +
85 "ArchivedFieldMetadataInstanceHolder (cause: archived flat/null-restricted field metadata) " +
86 "failed : app substituted a different version");
87 }
88
89 private static void testStaticField() throws Exception {
90 String pointClassFile = new File(System.getProperty("test.classes", "."),
91 "ArchivedFieldMetadataStaticPoint.class").getPath();
92
93 TestCommon.checkDump(TestCommon.dump(appJar,
94 appClasses,
95 "--enable-preview"));
96
97 OutputAnalyzer output = TestCommon.exec(appJar,
98 "--enable-preview",
99 "-Xlog:class+load,class+preload",
100 "ArchivedFieldMetadataStaticApp", pointClassFile);
101 TestCommon.checkExec(output);
102
103 output.shouldContain("Preloading of class ArchivedFieldMetadataStaticPoint during loading of shared class " +
104 "ArchivedFieldMetadataStaticHolder (cause: archived flat/null-restricted field metadata) " +
105 "failed : app substituted a different version");
106 }
107 }
108
109 class ArchivedFieldMetadataInstanceApp {
110 public static void main(String[] args) throws Throwable {
111 Path classFile = Path.of(args[0]);
112 byte[] classBytes = Files.readAllBytes(classFile);
113 Class<?> fieldClass = MethodHandles.lookup().defineClass(classBytes);
114
115 ArchivedFieldMetadataInstanceHolder holder = new ArchivedFieldMetadataInstanceHolder();
116
117 if (holder.p.getClass() != fieldClass) {
118 throw new RuntimeException("Mismatched field class");
119 }
120 }
121 }
122
123 class ArchivedFieldMetadataInstanceHolder {
124 @StrictInit
125 final ArchivedFieldMetadataInstancePoint p;
126
127 ArchivedFieldMetadataInstanceHolder() {
128 p = new ArchivedFieldMetadataInstancePoint();
129 super();
130 }
131 }
132
133 @LooselyConsistentValue
134 value class ArchivedFieldMetadataInstancePoint {
135 int x = 0;
136 int y = 0;
137 }
138
139 class ArchivedFieldMetadataStaticApp {
140 public static void main(String[] args) throws Throwable {
141 Path classFile = Path.of(args[0]);
142 byte[] classBytes = Files.readAllBytes(classFile);
143 Class<?> fieldClass = MethodHandles.lookup().defineClass(classBytes);
144
145 if (ArchivedFieldMetadataStaticHolder.p.getClass() != fieldClass) {
146 throw new RuntimeException("Mismatched static field class");
147 }
148 }
149 }
150
151 class ArchivedFieldMetadataStaticHolder {
152 @NullRestricted
153 static ArchivedFieldMetadataStaticPoint p = new ArchivedFieldMetadataStaticPoint();
154 }
155
156 value class ArchivedFieldMetadataStaticPoint {
157 int x = 0;
158 int y = 0;
159 }