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
|