Hi,
I suspect that the filename of a jar never gets into the error message
because the only place Manifest.jarFilename is assigned is in
Manifest.Manifest(JarVerifier,InputStream,String) only after a
successful call to Manifest.read by which the manifest is already fully
read and parsed and after which no error from reading and parsing it
could possibly occur any more.
The closest related bug I found is 8205525. I would have considered
filing a new bug if I had the privileges. For now, I put the existing
8205525 bug number in the @bug tag of the test.
Another flaw is that after the manifest has been read from the jar that
the jar file name is not reset and a subsequent call to Manifest.read
would report the name of the jar file of which the manifest was loaded
initially which is admittedly somewhat a strange form of use but
absolutely possible with the API as it currently is. I figure the jar
file name could go instead to Manifest.jarFilename be added to
Manifest.read as a new overloaded kind of optional parameter and then
be set in a new Manifest.FastInputStream member variable. Worth a bug?
I found an opening bracket missing in an error message fragment and
included it in the attached patch without a separate bug or patch.
Curiously looking forward to any comment,
Philipp
diff -r 7d1efad039a3 src/java.base/share/classes/java/util/jar/Manifest.java
--- a/src/java.base/share/classes/java/util/jar/Manifest.java Mon Jan 07 14:15:00 2019 -0500
+++ b/src/java.base/share/classes/java/util/jar/Manifest.java Mon Jan 07 23:31:55 2019 +0100
@@ -96,9 +96,10 @@
* Constructs a new Manifest from the specified input stream
* and associates it with a JarVerifier.
*/
- Manifest(JarVerifier jv, InputStream is, String jarFilename) throws IOException {
+ Manifest(JarVerifier jv, InputStream is, String jarFilename)
+ throws IOException {
+ this.jarFilename = jarFilename;
read(is);
- this.jarFilename = jarFilename;
this.jv = jv;
}
@@ -315,8 +316,8 @@
if (name == null) {
name = parseName(lbuf, len);
if (name == null) {
- throw new IOException("invalid manifest format"
- + getErrorPosition(jarFilename, lineNumber) + ")");
+ throw new IOException("invalid manifest format ("
+ + getErrorPosition(jarFilename, lineNumber) + ")");
}
if (fis.peek() == ' ') {
// name is wrapped
diff -r 7d1efad039a3 test/jdk/java/util/jar/JarFile/ReportErrorPositionFilename.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/util/jar/JarFile/ReportErrorPositionFilename.java Mon Jan 07 23:31:55 2019 +0100
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.concurrent.Callable;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.JarOutputStream;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+/**
+ * @test
+ * @bug 8205525
+ * @run main/othervm -Djdk.includeInExceptions=jar ReportErrorPositionFilename
+ * @summary Verifies that reading a jar file with an invalid manifest
+ * reports its name as part of the exception message given
+ * jdk.includeInExceptions=jar.
+ */
+/*
+ * @see Manifest#Manifest(JarVerifier,InputStream,String)
+ * @see Manifest#getErrorPosition
+ */
+public class ReportErrorPositionFilename {
+
+ static final String FILENAME = "Unique-Filename-Expected-In_Msg.jar";
+
+ static final byte[] INVALID_MANIFEST = (
+ "Manifest-Version: 1.0\r\n" +
+ "\r\n" +
+ "Illegal\r\n" +
+ "\r\n").getBytes(UTF_8);
+
+ static String createJarInvalidManifest(String jar) throws IOException {
+ try (OutputStream out = Files.newOutputStream(Paths.get(jar));
+ JarOutputStream jos = new JarOutputStream(out)) {
+ JarEntry je = new JarEntry(JarFile.MANIFEST_NAME);
+ jos.putNextEntry(je);
+ jos.write(INVALID_MANIFEST);
+ jos.closeEntry();
+ }
+ return jar;
+ }
+
+ static void test(Callable<?> attempt) throws Exception {
+ try {
+ attempt.call();
+ throw new AssertionError("expected exception");
+ } catch (IOException e) {
+ e.printStackTrace();
+ if (e.getMessage().indexOf(FILENAME) == -1) {
+ throw new AssertionError("file name not in error message");
+ }
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ test(() -> new JarFile(createJarInvalidManifest(
+ FILENAME)).getManifest());
+ test(() -> new JarFile(createJarInvalidManifest(
+ "Verifying-" + FILENAME), true).getManifest());
+ }
+
+}