8165723: JarFile::isMultiRelease() method returns false when it should return true
Reviewed-by: alanb
This commit is contained in:
parent
253489ea9a
commit
2ac4d6a7d3
@ -836,18 +836,25 @@ class JarFile extends ZipFile {
|
|||||||
private static final byte[] CLASSPATH_CHARS =
|
private static final byte[] CLASSPATH_CHARS =
|
||||||
{'C','L','A','S','S','-','P','A','T','H', ':', ' '};
|
{'C','L','A','S','S','-','P','A','T','H', ':', ' '};
|
||||||
|
|
||||||
// The bad character shift for "class-path:"
|
// The bad character shift for "class-path: "
|
||||||
private static final byte[] CLASSPATH_LASTOCC;
|
private static final byte[] CLASSPATH_LASTOCC;
|
||||||
|
|
||||||
|
// The good suffix shift for "class-path: "
|
||||||
|
private static final byte[] CLASSPATH_OPTOSFT;
|
||||||
|
|
||||||
private static final byte[] MULTIRELEASE_CHARS =
|
private static final byte[] MULTIRELEASE_CHARS =
|
||||||
{'M','U','L','T','I','-','R','E','L','E', 'A', 'S', 'E', ':',
|
{'M','U','L','T','I','-','R','E','L','E', 'A', 'S', 'E', ':',
|
||||||
' ', 'T', 'R', 'U', 'E'};
|
' ', 'T', 'R', 'U', 'E'};
|
||||||
|
|
||||||
// The bad character shift for "multi-release: "
|
// The bad character shift for "multi-release: true"
|
||||||
private static final byte[] MULTIRELEASE_LASTOCC;
|
private static final byte[] MULTIRELEASE_LASTOCC;
|
||||||
|
|
||||||
|
// The good suffix shift for "multi-release: true"
|
||||||
|
private static final byte[] MULTIRELEASE_OPTOSFT;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
CLASSPATH_LASTOCC = new byte[64];
|
CLASSPATH_LASTOCC = new byte[64];
|
||||||
|
CLASSPATH_OPTOSFT = new byte[12];
|
||||||
CLASSPATH_LASTOCC[(int)'C' - 32] = 1;
|
CLASSPATH_LASTOCC[(int)'C' - 32] = 1;
|
||||||
CLASSPATH_LASTOCC[(int)'L' - 32] = 2;
|
CLASSPATH_LASTOCC[(int)'L' - 32] = 2;
|
||||||
CLASSPATH_LASTOCC[(int)'S' - 32] = 5;
|
CLASSPATH_LASTOCC[(int)'S' - 32] = 5;
|
||||||
@ -858,8 +865,13 @@ class JarFile extends ZipFile {
|
|||||||
CLASSPATH_LASTOCC[(int)'H' - 32] = 10;
|
CLASSPATH_LASTOCC[(int)'H' - 32] = 10;
|
||||||
CLASSPATH_LASTOCC[(int)':' - 32] = 11;
|
CLASSPATH_LASTOCC[(int)':' - 32] = 11;
|
||||||
CLASSPATH_LASTOCC[(int)' ' - 32] = 12;
|
CLASSPATH_LASTOCC[(int)' ' - 32] = 12;
|
||||||
|
for (int i = 0; i < 11; i++) {
|
||||||
|
CLASSPATH_OPTOSFT[i] = 12;
|
||||||
|
}
|
||||||
|
CLASSPATH_OPTOSFT[11] = 1;
|
||||||
|
|
||||||
MULTIRELEASE_LASTOCC = new byte[64];
|
MULTIRELEASE_LASTOCC = new byte[64];
|
||||||
|
MULTIRELEASE_OPTOSFT = new byte[19];
|
||||||
MULTIRELEASE_LASTOCC[(int)'M' - 32] = 1;
|
MULTIRELEASE_LASTOCC[(int)'M' - 32] = 1;
|
||||||
MULTIRELEASE_LASTOCC[(int)'I' - 32] = 5;
|
MULTIRELEASE_LASTOCC[(int)'I' - 32] = 5;
|
||||||
MULTIRELEASE_LASTOCC[(int)'-' - 32] = 6;
|
MULTIRELEASE_LASTOCC[(int)'-' - 32] = 6;
|
||||||
@ -872,6 +884,11 @@ class JarFile extends ZipFile {
|
|||||||
MULTIRELEASE_LASTOCC[(int)'R' - 32] = 17;
|
MULTIRELEASE_LASTOCC[(int)'R' - 32] = 17;
|
||||||
MULTIRELEASE_LASTOCC[(int)'U' - 32] = 18;
|
MULTIRELEASE_LASTOCC[(int)'U' - 32] = 18;
|
||||||
MULTIRELEASE_LASTOCC[(int)'E' - 32] = 19;
|
MULTIRELEASE_LASTOCC[(int)'E' - 32] = 19;
|
||||||
|
for (int i = 0; i < 17; i++) {
|
||||||
|
MULTIRELEASE_OPTOSFT[i] = 19;
|
||||||
|
}
|
||||||
|
MULTIRELEASE_OPTOSFT[17] = 6;
|
||||||
|
MULTIRELEASE_OPTOSFT[18] = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
private JarEntry getManEntry() {
|
private JarEntry getManEntry() {
|
||||||
@ -913,7 +930,7 @@ class JarFile extends ZipFile {
|
|||||||
* Since there are no repeated substring in our search strings,
|
* Since there are no repeated substring in our search strings,
|
||||||
* the good suffix shifts can be replaced with a comparison.
|
* the good suffix shifts can be replaced with a comparison.
|
||||||
*/
|
*/
|
||||||
private int match(byte[] src, byte[] b, byte[] lastOcc) {
|
private int match(byte[] src, byte[] b, byte[] lastOcc, byte[] optoSft) {
|
||||||
int len = src.length;
|
int len = src.length;
|
||||||
int last = b.length - len;
|
int last = b.length - len;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
@ -926,9 +943,8 @@ class JarFile extends ZipFile {
|
|||||||
|
|
||||||
if (c != src[j]) {
|
if (c != src[j]) {
|
||||||
// no match
|
// no match
|
||||||
int goodShift = (j < len - 1) ? len : 1;
|
|
||||||
int badShift = lastOcc[c - 32];
|
int badShift = lastOcc[c - 32];
|
||||||
i += Math.max(j + 1 - badShift, goodShift);
|
i += Math.max(j + 1 - badShift, optoSft[j]);
|
||||||
continue next;
|
continue next;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -958,10 +974,11 @@ class JarFile extends ZipFile {
|
|||||||
if (manEntry != null) {
|
if (manEntry != null) {
|
||||||
byte[] b = getBytes(manEntry);
|
byte[] b = getBytes(manEntry);
|
||||||
hasClassPathAttribute = match(CLASSPATH_CHARS, b,
|
hasClassPathAttribute = match(CLASSPATH_CHARS, b,
|
||||||
CLASSPATH_LASTOCC) != -1;
|
CLASSPATH_LASTOCC, CLASSPATH_OPTOSFT) != -1;
|
||||||
// is this a multi-release jar file
|
// is this a multi-release jar file
|
||||||
if (MULTI_RELEASE_ENABLED) {
|
if (MULTI_RELEASE_ENABLED) {
|
||||||
int i = match(MULTIRELEASE_CHARS, b, MULTIRELEASE_LASTOCC);
|
int i = match(MULTIRELEASE_CHARS, b, MULTIRELEASE_LASTOCC,
|
||||||
|
MULTIRELEASE_OPTOSFT);
|
||||||
if (i != -1) {
|
if (i != -1) {
|
||||||
i += MULTIRELEASE_CHARS.length;
|
i += MULTIRELEASE_CHARS.length;
|
||||||
if (i < b.length) {
|
if (i < b.length) {
|
||||||
|
@ -23,23 +23,29 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* @test
|
* @test
|
||||||
* @bug 8132734 8144062
|
* @bug 8132734 8144062 8165723
|
||||||
* @summary Test the extended API and the aliasing additions in JarFile that
|
* @summary Test the extended API and the aliasing additions in JarFile that
|
||||||
* support multi-release jar files
|
* support multi-release jar files
|
||||||
* @library /lib/testlibrary/java/util/jar
|
* @library /lib/testlibrary/java/util/jar /lib/testlibrary/
|
||||||
* @build Compiler JarBuilder CreateMultiReleaseTestJars
|
* @build Compiler JarBuilder CreateMultiReleaseTestJars
|
||||||
|
* @build jdk.testlibrary.RandomFactory
|
||||||
* @run testng MultiReleaseJarAPI
|
* @run testng MultiReleaseJarAPI
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Random;
|
||||||
import java.util.jar.JarFile;
|
import java.util.jar.JarFile;
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipFile;
|
import java.util.zip.ZipFile;
|
||||||
|
|
||||||
|
import jdk.testlibrary.RandomFactory;
|
||||||
|
|
||||||
import org.testng.Assert;
|
import org.testng.Assert;
|
||||||
import org.testng.annotations.AfterClass;
|
import org.testng.annotations.AfterClass;
|
||||||
import org.testng.annotations.BeforeClass;
|
import org.testng.annotations.BeforeClass;
|
||||||
@ -48,12 +54,15 @@ import org.testng.annotations.Test;
|
|||||||
|
|
||||||
public class MultiReleaseJarAPI {
|
public class MultiReleaseJarAPI {
|
||||||
|
|
||||||
|
private static final Random RANDOM = RandomFactory.getRandom();
|
||||||
|
|
||||||
String userdir = System.getProperty("user.dir",".");
|
String userdir = System.getProperty("user.dir",".");
|
||||||
CreateMultiReleaseTestJars creator = new CreateMultiReleaseTestJars();
|
CreateMultiReleaseTestJars creator = new CreateMultiReleaseTestJars();
|
||||||
File unversioned = new File(userdir, "unversioned.jar");
|
File unversioned = new File(userdir, "unversioned.jar");
|
||||||
File multirelease = new File(userdir, "multi-release.jar");
|
File multirelease = new File(userdir, "multi-release.jar");
|
||||||
File signedmultirelease = new File(userdir, "signed-multi-release.jar");
|
File signedmultirelease = new File(userdir, "signed-multi-release.jar");
|
||||||
|
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public void initialize() throws Exception {
|
public void initialize() throws Exception {
|
||||||
creator.compileEntries();
|
creator.compileEntries();
|
||||||
@ -99,10 +108,35 @@ public class MultiReleaseJarAPI {
|
|||||||
testCustomMultiReleaseValue("true\r ", false);
|
testCustomMultiReleaseValue("true\r ", false);
|
||||||
testCustomMultiReleaseValue("true\n true", false);
|
testCustomMultiReleaseValue("true\n true", false);
|
||||||
testCustomMultiReleaseValue("true\r\n true", false);
|
testCustomMultiReleaseValue("true\r\n true", false);
|
||||||
|
|
||||||
|
// generate "random" Strings to use as extra attributes, and
|
||||||
|
// verify that Multi-Release: true is always properly matched
|
||||||
|
for (int i = 0; i < 100; i++) {
|
||||||
|
byte[] keyBytes = new byte[RANDOM.nextInt(70) + 1];
|
||||||
|
Arrays.fill(keyBytes, (byte)('a' + RANDOM.nextInt(24)));
|
||||||
|
byte[] valueBytes = new byte[RANDOM.nextInt(70) + 1];
|
||||||
|
Arrays.fill(valueBytes, (byte)('a' + RANDOM.nextInt(24)));
|
||||||
|
|
||||||
|
String key = new String(keyBytes, StandardCharsets.UTF_8);
|
||||||
|
String value = new String(valueBytes, StandardCharsets.UTF_8);
|
||||||
|
// test that Multi-Release: true anywhere in the manifest always
|
||||||
|
// return true
|
||||||
|
testCustomMultiReleaseValue("true", Map.of(key, value), true);
|
||||||
|
|
||||||
|
// test that we don't get any false positives
|
||||||
|
testCustomMultiReleaseValue("false", Map.of(key, value), false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void testCustomMultiReleaseValue(String value, boolean expected) throws Exception {
|
private void testCustomMultiReleaseValue(String value, boolean expected)
|
||||||
creator.buildCustomMultiReleaseJar("custom-mr.jar", value);
|
throws Exception {
|
||||||
|
testCustomMultiReleaseValue(value, Map.of(), expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testCustomMultiReleaseValue(String value,
|
||||||
|
Map<String, String> extraAttributes, boolean expected)
|
||||||
|
throws Exception {
|
||||||
|
creator.buildCustomMultiReleaseJar("custom-mr.jar", value, extraAttributes);
|
||||||
File custom = new File(userdir, "custom-mr.jar");
|
File custom = new File(userdir, "custom-mr.jar");
|
||||||
try (JarFile jf = new JarFile(custom, true, ZipFile.OPEN_READ, Runtime.version())) {
|
try (JarFile jf = new JarFile(custom, true, ZipFile.OPEN_READ, Runtime.version())) {
|
||||||
Assert.assertEquals(jf.isMultiRelease(), expected);
|
Assert.assertEquals(jf.isMultiRelease(), expected);
|
||||||
|
@ -88,12 +88,28 @@ public class CreateMultiReleaseTestJars {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void buildMultiReleaseJar() throws IOException {
|
public void buildMultiReleaseJar() throws IOException {
|
||||||
buildCustomMultiReleaseJar("multi-release.jar", "true");
|
JarBuilder jb = customMultiReleaseJar("multi-release.jar", "true");
|
||||||
|
addEntries(jb);
|
||||||
|
jb.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void buildCustomMultiReleaseJar(String filename, String multiReleaseValue) throws IOException {
|
private JarBuilder customMultiReleaseJar(String filename, String multiReleaseValue)
|
||||||
|
throws IOException {
|
||||||
JarBuilder jb = new JarBuilder(filename);
|
JarBuilder jb = new JarBuilder(filename);
|
||||||
jb.addAttribute("Multi-Release", multiReleaseValue);
|
jb.addAttribute("Multi-Release", multiReleaseValue);
|
||||||
|
return jb;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void buildCustomMultiReleaseJar(String filename, String multiReleaseValue,
|
||||||
|
Map<String, String> extraAttributes) throws IOException {
|
||||||
|
JarBuilder jb = new JarBuilder(filename);
|
||||||
|
extraAttributes.entrySet()
|
||||||
|
.forEach(entry -> jb.addAttribute(entry.getKey(), entry.getValue()));
|
||||||
|
jb.addAttribute("Multi-Release", multiReleaseValue);
|
||||||
|
jb.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addEntries(JarBuilder jb) {
|
||||||
jb.addEntry("README", readme8.getBytes());
|
jb.addEntry("README", readme8.getBytes());
|
||||||
jb.addEntry("version/Main.java", main.getBytes());
|
jb.addEntry("version/Main.java", main.getBytes());
|
||||||
jb.addEntry("version/Main.class", rootClasses.get("version.Main"));
|
jb.addEntry("version/Main.class", rootClasses.get("version.Main"));
|
||||||
@ -107,26 +123,6 @@ public class CreateMultiReleaseTestJars {
|
|||||||
jb.addEntry("META-INF/versions/10/README", readme10.getBytes());
|
jb.addEntry("META-INF/versions/10/README", readme10.getBytes());
|
||||||
jb.addEntry("META-INF/versions/10/version/Version.java", java10.getBytes());
|
jb.addEntry("META-INF/versions/10/version/Version.java", java10.getBytes());
|
||||||
jb.addEntry("META-INF/versions/10/version/Version.class", version10Classes.get("version.Version"));
|
jb.addEntry("META-INF/versions/10/version/Version.class", version10Classes.get("version.Version"));
|
||||||
jb.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void buildShortMultiReleaseJar() throws IOException {
|
|
||||||
JarBuilder jb = new JarBuilder("short-multi-release.jar");
|
|
||||||
jb.addAttribute("Multi-Release", "true");
|
|
||||||
jb.addEntry("README", readme8.getBytes());
|
|
||||||
jb.addEntry("version/Main.java", main.getBytes());
|
|
||||||
jb.addEntry("version/Main.class", rootClasses.get("version.Main"));
|
|
||||||
jb.addEntry("version/Version.java", java8.getBytes());
|
|
||||||
jb.addEntry("version/Version.class", rootClasses.get("version.Version"));
|
|
||||||
jb.addEntry("META-INF/versions/9/README", readme9.getBytes());
|
|
||||||
jb.addEntry("META-INF/versions/9/version/Version.java", java9.getBytes());
|
|
||||||
jb.addEntry("META-INF/versions/9/version/PackagePrivate.java", ppjava9.getBytes());
|
|
||||||
// no entry for META-INF/versions/9/version/Version.class
|
|
||||||
jb.addEntry("META-INF/versions/9/version/PackagePrivate.class", version9Classes.get("version.PackagePrivate"));
|
|
||||||
jb.addEntry("META-INF/versions/10/README", readme10.getBytes());
|
|
||||||
jb.addEntry("META-INF/versions/10/version/Version.java", java10.getBytes());
|
|
||||||
jb.addEntry("META-INF/versions/10/version/Version.class", version10Classes.get("version.Version"));
|
|
||||||
jb.build();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void buildSignedMultiReleaseJar() throws Exception {
|
public void buildSignedMultiReleaseJar() throws Exception {
|
||||||
|
Loading…
Reference in New Issue
Block a user