Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8367444

Various file descriptor leaks from a jar:file:// URL

XMLWordPrintable

    • generic
    • generic

      A DESCRIPTION OF THE PROBLEM :
      This might appear to be a duplicate of JDK-6956385, but it is not as that one was attempted to be fixed with Java 22, but it seems it was not or got broken again and also has more leaks.

      Using the https://github.com/jenkinsci/lib-file-leak-detector/ (but it also happens without, verified by trying to delete a file on Windows and not being able to, then investigating with the leak detector), you can see that with the three lines below a file descriptor is leaking because querying any "header" value like last modified or content type opens the input stream which then is never closed.

      Getting the actual input stream from the url connection (of which you maybe not even know that it is a jar url connection on a file url connection) and closing it, even if you are not at all interested in the input stream, just because the file url connection uses that input stream internally like for the sibling issue on file: URLs I just reported feels quite wrong and unintuitive.

      Additionally that does not fix the problem in this case.
      Instead of fixing the file descriptor leak, it produces two new file descriptor leaks on the same file.


      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      - Use the below code with an existing JAR file with manifest file
      - Use the file leak detector or set a breakpoint after the third line and find that the file descriptor leaks
      - Add `conn.getInputStream().close()` after the last line the leaked file descriptor is closed together with the input stream you never wanted to retrieve

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      No file descriptor leak
      ACTUAL -
      - 1 file descriptor leak without the inputstream getting and closing (#3 below)
      - 3 file descriptor leaks with the inputstream getting and closing

      3 descriptors are open
      #1 path/to/some/existing.jar by thread:main on Tue Sep 09 17:56:41 CEST 2025
      at java.base/java.io.RandomAccessFile.<init>(RandomAccessFile.java:212)
      at java.base/java.util.zip.ZipFile$Source.<init>(ZipFile.java:1494)
      at java.base/java.util.zip.ZipFile$Source.get(ZipFile.java:1460)
      at java.base/java.util.zip.ZipFile$CleanableResource.<init>(ZipFile.java:671)
      at java.base/java.util.zip.ZipFile.<init>(ZipFile.java:201)
      at java.base/java.util.zip.ZipFile.<init>(ZipFile.java:148)
      at java.base/java.util.jar.JarFile.<init>(JarFile.java:333)
      at java.base/sun.net.www.protocol.jar.URLJarFile.&lt;init&gt;(URLJarFile.java:70)
      at java.base/sun.net.www.protocol.jar.URLJarFile.getJarFile(URLJarFile.java:56)
      at java.base/sun.net.www.protocol.jar.JarFileFactory.getOrCreate(JarFileFactory.java:107)
      at java.base/sun.net.www.protocol.jar.JarURLConnection.connect(JarURLConnection.java:117)
      at java.base/sun.net.www.protocol.jar.JarURLConnection.getInputStream(JarURLConnection.java:160)
      at foo.Foo.main(Foo.java:13)
      #2 path/to/some/existing.jar by thread:main on Tue Sep 09 17:56:41 CEST 2025
      at java.base/java.util.zip.ZipFile.<init>(ZipFile.java:149)
      at java.base/java.util.jar.JarFile.<init>(JarFile.java:333)
      at java.base/sun.net.www.protocol.jar.URLJarFile.&lt;init&gt;(URLJarFile.java:70)
      at java.base/sun.net.www.protocol.jar.URLJarFile.getJarFile(URLJarFile.java:56)
      at java.base/sun.net.www.protocol.jar.JarFileFactory.getOrCreate(JarFileFactory.java:107)
      at java.base/sun.net.www.protocol.jar.JarURLConnection.connect(JarURLConnection.java:117)
      at java.base/sun.net.www.protocol.jar.JarURLConnection.getInputStream(JarURLConnection.java:160)
      at foo.Foo.main(Foo.java:13)
      #3 path/to/some/existing.jar by thread:main on Tue Sep 09 17:56:41 CEST 2025
      at java.base/java.io.FileInputStream.<init>(FileInputStream.java:141)
      at java.base/java.io.FileInputStream.<init>(FileInputStream.java:109)
      at java.base/sun.net.www.protocol.file.FileURLConnection.connect(FileURLConnection.java:83)
      at java.base/sun.net.www.protocol.file.FileURLConnection.initializeHeaders(FileURLConnection.java:102)
      at java.base/sun.net.www.protocol.file.FileURLConnection.getHeaderField(FileURLConnection.java:143)
      at java.base/sun.net.www.protocol.jar.JarURLConnection.getHeaderField(JarURLConnection.java:240)
      at java.base/java.net.URLConnection.getHeaderFieldDate(URLConnection.java:662)
      at java.base/java.net.URLConnection.getLastModified(URLConnection.java:555)
      at foo.Foo.main(Foo.java:12)

      ---------- BEGIN SOURCE ----------
      URL url = URI.create("jar:file:///path/to/some/existing.jar!/META-INF/MANIFEST.MF").toURL();
      URLConnection conn = url.openConnection();
      conn.getLastModified();
      ---------- END SOURCE ----------

        1. JarLeakRepro.java
          0.9 kB
          Cody Gaffney

            Unassigned Unassigned
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated: