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

(fc) Async close of streams connected to uninterruptible FileChannel doesn't throw AsynchonrousCloseException in all cases

XMLWordPrintable

    • generic
    • generic

      ADDITIONAL SYSTEM INFORMATION :
      openjdk version "25-ea" 2025-09-16
      OpenJDK Runtime Environment (build 25-ea+30-3419)
      OpenJDK 64-Bit Server VM (build 25-ea+30-3419, mixed mode, sharing)

      A DESCRIPTION OF THE PROBLEM :
      The documentation of `InputStream::available` states that:
      ```
           * @return an estimate of the number of bytes that can be read (or
           * skipped over) from this input stream without blocking or
           * {@code 0} when it reaches the end of the input stream.
      ```
      However, in some rare cases `sun.nio.ch.ChannelInputStream` may return -1 if the channel is FileChannelImpl:
      ```

          /**
           * Returns an estimate of the number of remaining bytes that can be read
           * from this channel without blocking.
           */
          public int available() throws IOException {
              ensureOpen();
              synchronized (positionLock) {
                  int a = -1;
                  int ti = -1;
                  try {
                      beginBlocking();
                      ti = threads.add();
                      if (!isOpen())
                          return -1; // <---
                      a = nd.available(fd);
                  } finally {
                      threads.remove(ti);
                      endBlocking(a > -1);
                  }
                  return a;
              }
          }
      ```
      Probably appeared after JDK-8233451.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Run the attached program.
      Replace path to a test file, if needed.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      The program keeps running.
      ACTUAL -
      `Violation` is printed in the terminal.

      ---------- BEGIN SOURCE ----------
      import java.io.IOException;
      import java.io.InputStream;
      import java.nio.file.FileAlreadyExistsException;
      import java.nio.file.Files;
      import java.nio.file.Path;
      import java.util.concurrent.ConcurrentLinkedQueue;

      public class ChannelInputStreamTest {

      public static void main(String[] args) throws IOException {
      System.out.println(Runtime.version());
      var close = new ConcurrentLinkedQueue<InputStream>();
      Thread.ofPlatform().start(() -> {
      do {
      InputStream in;
      if ((in = close.poll()) != null)
      try {
      in.close();
      } catch (IOException ignored) {
      }
      } while (true);
      });
      var path = Path.of("F:\\file.txt");
      Files.createDirectories(path.getParent());
      try {
      Files.createFile(path);
      } catch (FileAlreadyExistsException ignored) {
      }
      Thread.ofPlatform().start(() -> {
      do {
      InputStream in;
      try {
      in = Files.newInputStream(path);
      } catch (IOException ignored) {
      continue;
      }
      close.offer(in);
      int available;
      try {
      available = in.available();
      } catch (Throwable t) {
      continue;
      }
      if (available < 0) {
      System.err.println("Violation");
      Runtime.getRuntime().halt(1);
      }
      } while (true);
      });
      }
      }

      ---------- END SOURCE ----------

        1. ChannelInputStreamTest.java
          1 kB
          Andrew Wang
        2. fci.patch
          0.7 kB
          Alan Bateman

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

              Created:
              Updated: