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

FileOutputStream.close() re-entrantly invokes itself after getChannel().force()

XMLWordPrintable

    • generic
    • generic

      ADDITIONAL SYSTEM INFORMATION :
      OS X arm64
      $ openjdk version "18.0.2" 2022-07-19
      OpenJDK Runtime Environment Homebrew (build 18.0.2+0)
      OpenJDK 64-Bit Server VM Homebrew (build 18.0.2+0, mixed mode, sharing)

      A DESCRIPTION OF THE PROBLEM :
      In certain situations, FileOutputStream.close() re-entrantly (i.e., recursively) invokes itself.

      This behavior is horrible as it creates havoc for any sub-classes of FileOutputStream that override close() in order to perform any work at that point in lifecycle of the stream. At the very least, it's undocumented.

      I have verified this bug occurs in: JDK 1.8.0_312, JDK 11.0.16, and JDK 18.0.2.
      This bug occurs in JDK 8 It does occur in JDK 11, JDK 18.0.2, and presumably all versions in between.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Run the test program below.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      java.lang.Throwable: close() invoked here
      at ReentrantClose.close(ReentrantClose.java:12)
      at ReentrantClose.main(ReentrantClose.java:19)
      ACTUAL -
      java.lang.Throwable: close() invoked here
      at ReentrantClose.close(ReentrantClose.java:12)
      at ReentrantClose.main(ReentrantClose.java:19)
      java.lang.Throwable: close() invoked here
      at ReentrantClose.close(ReentrantClose.java:12)
      at java.base/sun.nio.ch.FileChannelImpl.implCloseChannel(FileChannelImpl.java:202)
      at java.base/java.nio.channels.spi.AbstractInterruptibleChannel.close(AbstractInterruptibleChannel.java:112)
      at java.base/java.io.FileOutputStream.close(FileOutputStream.java:387)
      at ReentrantClose.close(ReentrantClose.java:13)
      at ReentrantClose.main(ReentrantClose.java:19)

      ---------- BEGIN SOURCE ----------
      import java.io.*;


      public class ReentrantClose extends FileOutputStream {

          public ReentrantClose(String filename) throws FileNotFoundException {
              super(filename);
          }

          @Override
          public void close() throws IOException {
              new Throwable("close() invoked here").printStackTrace(System.out);
              super.close();
          }

          public static void main(String[] args) throws Exception {
              try (ReentrantClose out = new ReentrantClose("testfile")) {
                  out.getChannel().force(false); // this line triggers re-entrant invocation of close()
              }
          }
      }
      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      None known.

      FREQUENCY : always


            bpb Brian Burkhalter
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            6 Start watching this issue

              Created:
              Updated:
              Resolved: