8153213: Jar manifest attribute "Multi-Release" accepts any value

Reviewed-by: psandoz, redestad
This commit is contained in:
Steve Drach 2016-04-12 18:25:10 +02:00 committed by Claes Redestad
parent 636213d1c9
commit f767b8ce19
3 changed files with 69 additions and 14 deletions

View File

@ -894,7 +894,8 @@ class JarFile extends ZipFile {
private static final byte[] CLASSPATH_LASTOCC;
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'};
// The bad character shift for "multi-release: "
private static final byte[] MULTIRELEASE_LASTOCC;
@ -914,17 +915,17 @@ class JarFile extends ZipFile {
MULTIRELEASE_LASTOCC = new byte[64];
MULTIRELEASE_LASTOCC[(int)'M' - 32] = 1;
MULTIRELEASE_LASTOCC[(int)'U' - 32] = 2;
MULTIRELEASE_LASTOCC[(int)'T' - 32] = 4;
MULTIRELEASE_LASTOCC[(int)'I' - 32] = 5;
MULTIRELEASE_LASTOCC[(int)'-' - 32] = 6;
MULTIRELEASE_LASTOCC[(int)'R' - 32] = 7;
MULTIRELEASE_LASTOCC[(int)'L' - 32] = 9;
MULTIRELEASE_LASTOCC[(int)'A' - 32] = 11;
MULTIRELEASE_LASTOCC[(int)'S' - 32] = 12;
MULTIRELEASE_LASTOCC[(int)'E' - 32] = 13;
MULTIRELEASE_LASTOCC[(int)':' - 32] = 14;
MULTIRELEASE_LASTOCC[(int)' ' - 32] = 15;
MULTIRELEASE_LASTOCC[(int)'T' - 32] = 16;
MULTIRELEASE_LASTOCC[(int)'R' - 32] = 17;
MULTIRELEASE_LASTOCC[(int)'U' - 32] = 18;
MULTIRELEASE_LASTOCC[(int)'E' - 32] = 19;
}
private JarEntry getManEntry() {
@ -966,7 +967,7 @@ class JarFile extends ZipFile {
* Since there are no repeated substring in our search strings,
* the good suffix shifts can be replaced with a comparison.
*/
private boolean match(byte[] src, byte[] b, byte[] lastOcc) {
private int match(byte[] src, byte[] b, byte[] lastOcc) {
int len = src.length;
int last = b.length - len;
int i = 0;
@ -990,9 +991,9 @@ class JarFile extends ZipFile {
continue next;
}
}
return true;
return i;
}
return false;
return -1;
}
/**
@ -1011,11 +1012,35 @@ class JarFile extends ZipFile {
if (manEntry != null) {
byte[] b = getBytes(manEntry);
hasClassPathAttribute = match(CLASSPATH_CHARS, b,
CLASSPATH_LASTOCC);
CLASSPATH_LASTOCC) != -1;
// is this a multi-release jar file
if (MULTI_RELEASE_ENABLED && version != BASE_VERSION) {
isMultiRelease = match(MULTIRELEASE_CHARS, b,
MULTIRELEASE_LASTOCC);
int i = match(MULTIRELEASE_CHARS, b, MULTIRELEASE_LASTOCC);
if (i != -1) {
i += MULTIRELEASE_CHARS.length;
if (i < b.length) {
byte c = b[i++];
// Check that the value is followed by a newline
// and does not have a continuation
if (c == '\n' &&
(i == b.length || b[i] != ' ')) {
isMultiRelease = true;
} else if (c == '\r') {
if (i == b.length) {
isMultiRelease = true;
} else {
c = b[i++];
if (c == '\n') {
if (i == b.length || b[i] != ' ') {
isMultiRelease = true;
}
} else if (c != ' ') {
isMultiRelease = true;
}
}
}
}
}
}
}
hasCheckedSpecialAttributes = true;

View File

@ -54,6 +54,7 @@ public class MultiReleaseJarAPI {
static final int MAJOR_VERSION = Version.current().major();
String userdir = System.getProperty("user.dir",".");
CreateMultiReleaseTestJars creator = new CreateMultiReleaseTestJars();
File unversioned = new File(userdir, "unversioned.jar");
File multirelease = new File(userdir, "multi-release.jar");
File signedmultirelease = new File(userdir, "signed-multi-release.jar");
@ -62,7 +63,6 @@ public class MultiReleaseJarAPI {
@BeforeClass
public void initialize() throws Exception {
CreateMultiReleaseTestJars creator = new CreateMultiReleaseTestJars();
creator.compileEntries();
creator.buildUnversionedJar();
creator.buildMultiReleaseJar();
@ -82,6 +82,10 @@ public class MultiReleaseJarAPI {
Assert.assertFalse(jf.isMultiRelease());
}
try (JarFile jf = new JarFile(unversioned, true, ZipFile.OPEN_READ, Release.RUNTIME)) {
Assert.assertFalse(jf.isMultiRelease());
}
try (JarFile jf = new JarFile(multirelease)) {
Assert.assertFalse(jf.isMultiRelease());
}
@ -89,6 +93,28 @@ public class MultiReleaseJarAPI {
try (JarFile jf = new JarFile(multirelease, true, ZipFile.OPEN_READ, Release.RUNTIME)) {
Assert.assertTrue(jf.isMultiRelease());
}
testCustomMultiReleaseValue("true", true);
testCustomMultiReleaseValue("true\r\nOther: value", true);
testCustomMultiReleaseValue("true\nOther: value", true);
testCustomMultiReleaseValue("true\rOther: value", true);
testCustomMultiReleaseValue("false", false);
testCustomMultiReleaseValue(" true", false);
testCustomMultiReleaseValue("true ", false);
testCustomMultiReleaseValue("true\n ", false);
testCustomMultiReleaseValue("true\r ", false);
testCustomMultiReleaseValue("true\n true", false);
testCustomMultiReleaseValue("true\r\n true", false);
}
private void testCustomMultiReleaseValue(String value, boolean expected) throws Exception {
creator.buildCustomMultiReleaseJar("custom-mr.jar", value);
File custom = new File(userdir, "custom-mr.jar");
try (JarFile jf = new JarFile(custom, true, ZipFile.OPEN_READ, Release.RUNTIME)) {
Assert.assertEquals(jf.isMultiRelease(), expected);
}
Files.delete(custom.toPath());
}
@Test

View File

@ -88,8 +88,12 @@ public class CreateMultiReleaseTestJars {
}
public void buildMultiReleaseJar() throws IOException {
JarBuilder jb = new JarBuilder("multi-release.jar");
jb.addAttribute("Multi-Release", "true");
buildCustomMultiReleaseJar("multi-release.jar", "true");
}
public void buildCustomMultiReleaseJar(String filename, String multiReleaseValue) throws IOException {
JarBuilder jb = new JarBuilder(filename);
jb.addAttribute("Multi-Release", multiReleaseValue);
jb.addEntry("README", readme8.getBytes());
jb.addEntry("version/Main.java", main.getBytes());
jb.addEntry("version/Main.class", rootClasses.get("version.Main"));