JDK-8211765 : JarFile constructor throws undocumented java.nio.file.InvalidPathException
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.util.jar
  • Affected Version: 11
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: os_x
  • CPU: x86
  • Submitted: 2018-10-05
  • Updated: 2019-05-16
  • Resolved: 2018-10-07
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 11 JDK 12
11.0.2Fixed 12 b15Fixed
Description
ADDITIONAL SYSTEM INFORMATION :
openjdk version "11" 2018-09-25
OpenJDK Runtime Environment 18.9 (build 11+28)
OpenJDK 64-Bit Server VM 18.9 (build 11+28, mixed mode)

A DESCRIPTION OF THE PROBLEM :
This was raised in the OpenJDK core-libs-dev mailing list and was acknowledged as a bug http://mail.openjdk.java.net/pipermail/core-libs-dev/2018-October/055859.html. Although the discussion started off as a Windows OS specific issue, later in that thread, Alan rightly pointed out that this isn't Windows specific. Details of the bug are as follows:

Please consider the following trivial code:

import java.util.jar.*;
import java.io.*;

public class JarFileTest {
    public static void main(final String[] args) throws Exception {
        final String tmpDir = System.getProperty("java.io.tmpdir");
        try {
            final JarFile jarFile = new JarFile(tmpDir + File.separator
+ "*");
        } catch (IOException ioe) {
            System.out.println("Got the expected IOException " + ioe);
        }
    }
}

The constructor of the JarFile is passed a string which intentionally is
an (wildcard) invalid path. The above code (as expected) throws an
IOException on *nix systems across various version of Java (tested
against Java 8, 11). The same code throws an IOException (as expected)
in Java 8 on Windows OS too. However, in Java 11, on Windows OS, this
code throws a different exception (java.nio.file.InvalidPathException)
which isn't IOException or a subclass of it:

Exception in thread "main" java.nio.file.InvalidPathException: Illegal
char <*> at index 38: C:\Users\someone\AppData\Local\Temp\1\*
at
java.base/sun.nio.fs.WindowsPathParser.normalize(WindowsPathParser.java:182)
at java.base/sun.nio.fs.WindowsPathParser.parse(WindowsPathParser.java:153)
at java.base/sun.nio.fs.WindowsPathParser.parse(WindowsPathParser.java:77)
at java.base/sun.nio.fs.WindowsPath.parse(WindowsPath.java:92)
at
java.base/sun.nio.fs.WindowsFileSystem.getPath(WindowsFileSystem.java:229)
at java.base/java.io.File.toPath(File.java:2290)
at java.base/java.util.zip.ZipFile$Source.get(ZipFile.java:1220)
at
java.base/java.util.zip.ZipFile$CleanableResource.<init>(ZipFile.java:727)
at java.base/java.util.zip.ZipFile$CleanableResource.get(ZipFile.java:845)
at java.base/java.util.zip.ZipFile.<init>(ZipFile.java:245)
at java.base/java.util.zip.ZipFile.<init>(ZipFile.java:175)
at java.base/java.util.jar.JarFile.<init>(JarFile.java:341)
at java.base/java.util.jar.JarFile.<init>(JarFile.java:312)
at java.base/java.util.jar.JarFile.<init>(JarFile.java:251)
at JarFileTest.main(JarFileTest.java:8)


The javadoc of JarFile constructor(s) mentions that:

     * @throws IOException if an I/O error has occurred

Given that the javadoc doesn't mention anything about this other
exception, would this throwing of java.nio.file.InvalidPathException be
considered a bug in the implementation?

If this indeed is considered a bug, it appears to be the code in
java.util.zip.ZipFile$Source.get method which calls File#toPath(), which
as per its javadoc is indeed expected to throw an
java.nio.file.InvalidPathException if a Path cannot be constructed out
of the File. Looking at the implementation of the underlying
java.nio.file.FileSystem on *nix and Windows, they differ when it comes
to whether or not the exception gets thrown (Unix one seems to always
return a result). But keeping the implementation of
java.nio.file.FileSystem aside, I guess the
java.util.zip.ZipFile$Source.get code needs to have a catch block for
the InvalidPathException to wrap that into a IOException? Something like:


# HG changeset patch
# User Jaikiran Pai <jaikiran.pai@gmail.com>
# Date 1538645309 -19800
#      Thu Oct 04 14:58:29 2018 +0530
# Node ID ff1bfd8cc9a3b385716fa5191bb68989d552f87e
# Parent  8705c6d536c5c197d0210acccf145ebc48f90227
Wrap and throw an IOException when a InvalidPathException is thrown

diff --git a/src/java.base/share/classes/java/util/zip/ZipFile.java
b/src/java.base/share/classes/java/util/zip/ZipFile.java
--- a/src/java.base/share/classes/java/util/zip/ZipFile.java
+++ b/src/java.base/share/classes/java/util/zip/ZipFile.java
@@ -35,6 +35,7 @@
 import java.lang.ref.Cleaner.Cleanable;
 import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
+import java.nio.file.InvalidPathException;
 import java.nio.file.attribute.BasicFileAttributes;
 import java.nio.file.Files;
 import java.util.ArrayDeque;
@@ -1218,8 +1219,13 @@
 
 
         static Source get(File file, boolean toDelete) throws IOException {
-            Key key = new Key(file,
-                              Files.readAttributes(file.toPath(),
BasicFileAttributes.class));
+            final Key key;
+            try {
+                key = new Key(file,
+                        Files.readAttributes(file.toPath(),
BasicFileAttributes.class));
+            } catch (InvalidPathException ipe) {
+                throw new IOException(ipe);
+            }
             Source src;
             synchronized (files) {
                 src = files.get(key);


Any thoughts?






REGRESSION : Last worked in version 8u172

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
A java.io.IOException is expected to be thrown from the JarFIle constructor
ACTUAL -
A java.nio.file.InvalidPathException is thrown instead

---------- BEGIN SOURCE ----------
For Windows OS:

import java.util.jar.*;
import java.io.*;

public class JarFileTest {
	public static void main(final String[] args) throws Exception {
		final String tmpDir = System.getProperty("java.io.tmpdir");
		try {
			final JarFile jarFile = new JarFile(tmpDir + File.separator + "*");
		} catch (IOException ioe) {
			System.out.println("Got the expected IOException " + ioe);
		}
	}
}


For *nix OS:

import java.util.jar.*;
import java.io.*;

public class JarFileTest {
	public static void main(final String[] args) throws Exception {
		final String tmpDir = System.getProperty("java.io.tmpdir");
		try {
			final JarFile jarFile = new JarFile(tmpDir + File.separator + "abc\0xyz");
		} catch (IOException ioe) {
			System.out.println("Got the expected IOException " + ioe);
		}
	}
}
---------- END SOURCE ----------

FREQUENCY : always



Comments
Fix Request Backporting this fix makes 11u more reliable. Patch applies cleanly to 11u. Unpatched 11u fails new regression test. Patched 11u passes new regression test, and jdk/java/util/jar tests.
18-02-2019