Skip to content

Commit 4ab869e

Browse files
rvansaYuri Nesterenko
authored andcommitted
8296329: jar validator doesn't account for minor class file version
Reviewed-by: yan Backport-of: faf48e61be4f97f725b053aa351d3c64638546bf
1 parent ceabaee commit 4ab869e

File tree

3 files changed

+126
-4
lines changed

3 files changed

+126
-4
lines changed

src/jdk.jartool/share/classes/sun/tools/jar/FingerPrint.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ public boolean isIdentical(FingerPrint that) {
105105
}
106106

107107
public boolean isCompatibleVersion(FingerPrint that) {
108-
return attrs.version >= that.attrs.version;
108+
return attrs.majorVersion >= that.attrs.majorVersion;
109109
}
110110

111111
public boolean isSameAPI(FingerPrint that) {
@@ -236,7 +236,7 @@ private static final class ClassAttributes extends ClassVisitor {
236236
private String name;
237237
private String outerClassName;
238238
private String superName;
239-
private int version;
239+
private int majorVersion;
240240
private int access;
241241
private boolean publicClass;
242242
private boolean nestedClass;
@@ -255,7 +255,7 @@ private boolean isPublic(int access) {
255255
@Override
256256
public void visit(int version, int access, String name, String signature,
257257
String superName, String[] interfaces) {
258-
this.version = version;
258+
this.majorVersion = version & 0xFFFF; // JDK-8296329: extract major version only
259259
this.access = access;
260260
this.name = name;
261261
this.nestedClass = name.contains("$");

test/jdk/tools/jar/multiRelease/MRTestBase.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,10 @@ protected void compare(String jarfile,
102102
}
103103

104104
void javac(Path dest, Path... sourceFiles) throws Throwable {
105+
javac(dest, List.of(), sourceFiles);
106+
}
107+
108+
void javac(Path dest, List<String> extraParameters, Path... sourceFiles) throws Throwable {
105109

106110
List<String> commands = new ArrayList<>();
107111
String opts = System.getProperty("test.compiler.opts");
@@ -114,6 +118,7 @@ void javac(Path dest, Path... sourceFiles) throws Throwable {
114118
Stream.of(sourceFiles)
115119
.map(Object::toString)
116120
.forEach(x -> commands.add(x));
121+
commands.addAll(extraParameters);
117122

118123
StringWriter sw = new StringWriter();
119124
try (PrintWriter pw = new PrintWriter(sw)) {
@@ -122,7 +127,6 @@ void javac(Path dest, Path... sourceFiles) throws Throwable {
122127
throw new RuntimeException(sw.toString());
123128
}
124129
}
125-
126130
}
127131

128132
OutputAnalyzer jarWithStdin(File stdinSource,
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
/*
2+
* Copyright (c) 2022, 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+
* @test
26+
# @bug 8296329
27+
* @summary Tests for version validator.
28+
* @library /test/lib
29+
* @modules java.base/jdk.internal.misc
30+
* jdk.compiler
31+
* jdk.jartool
32+
* @build jdk.test.lib.Utils
33+
* jdk.test.lib.Asserts
34+
* jdk.test.lib.JDKToolFinder
35+
* jdk.test.lib.JDKToolLauncher
36+
* jdk.test.lib.Platform
37+
* jdk.test.lib.process.*
38+
* MRTestBase
39+
* @run testng/timeout=1200 VersionValidatorTest
40+
*/
41+
42+
import org.testng.annotations.BeforeMethod;
43+
import org.testng.annotations.DataProvider;
44+
import org.testng.annotations.Test;
45+
46+
import java.lang.reflect.Method;
47+
import java.nio.file.Files;
48+
import java.nio.file.Path;
49+
import java.nio.file.Paths;
50+
import java.util.List;
51+
52+
public class VersionValidatorTest extends MRTestBase {
53+
private Path root;
54+
55+
@BeforeMethod
56+
void testInit(Method method) {
57+
root = Paths.get(method.getName());
58+
}
59+
60+
@Test(dataProvider = "differentMajorVersions")
61+
public void onlyCompatibleVersionIsAllowedInMultiReleaseJar(String baseMajorVersion, String otherMajorVersion,
62+
boolean enablePreviewForBaseVersion, boolean enablePreviewForOtherVersion, boolean isAcceptable)
63+
throws Throwable {
64+
Path baseVersionClassesDir = compileLibClass(baseMajorVersion, enablePreviewForBaseVersion);
65+
Path otherVersionClassesDir = compileLibClass(otherMajorVersion, enablePreviewForOtherVersion);
66+
67+
var result = jar("--create", "--file", "lib.jar", "-C", baseVersionClassesDir.toString(), "Lib.class",
68+
"--release", otherMajorVersion, "-C", otherVersionClassesDir.toString(), "Lib.class");
69+
70+
if (isAcceptable) {
71+
result.shouldHaveExitValue(SUCCESS)
72+
.shouldBeEmptyIgnoreVMWarnings();
73+
} else {
74+
result.shouldNotHaveExitValue(SUCCESS)
75+
.shouldContain("has a class version incompatible with an earlier version");
76+
}
77+
}
78+
79+
private Path compileLibClass(String majorVersion, boolean enablePreview) throws Throwable {
80+
String classTemplate = """
81+
public class Lib {
82+
public static int version = $VERSION;
83+
}
84+
""";
85+
86+
Path sourceFile = Files.createDirectories(root.resolve("src").resolve(majorVersion)).resolve("Lib.java");
87+
Files.write(sourceFile, classTemplate.replace("$VERSION", majorVersion).getBytes());
88+
89+
Path classesDir = root.resolve("classes").resolve(majorVersion);
90+
91+
javac(classesDir, List.of("--release", majorVersion), sourceFile);
92+
if (enablePreview) {
93+
rewriteMinorVersionForEnablePreviewClass(classesDir.resolve("Lib.class"));
94+
}
95+
return classesDir;
96+
}
97+
98+
private void rewriteMinorVersionForEnablePreviewClass(Path classFile) throws Throwable {
99+
byte[] classBytes = Files.readAllBytes(classFile);
100+
classBytes[4] = -1;
101+
classBytes[5] = -1;
102+
Files.write(classFile, classBytes);
103+
}
104+
105+
@DataProvider
106+
Object[][] differentMajorVersions() {
107+
return new Object[][] {
108+
{ "16", "17", false, true, true },
109+
{ "16", "17", false, false, true },
110+
{ "16", "17", true, true, true },
111+
{ "16", "17", true, false, true },
112+
{ "17", "16", false, true, false },
113+
{ "17", "16", false, false, false },
114+
{ "17", "16", true, true, false },
115+
{ "17", "16", true, false, false },
116+
};
117+
}
118+
}

0 commit comments

Comments
 (0)