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

InflaterInputStream.available() returns 1 even when underlying Inflater is finished

XMLWordPrintable

      FULL PRODUCT VERSION :
      java version "1.8.0_102"
      Java(TM) SE Runtime Environment (build 1.8.0_102-b14)
      Java HotSpot(TM) 64-Bit Server VM (build 25.102-b14, mixed mode)


      ADDITIONAL OS VERSION INFORMATION :
      Linux rrosenbl-ld1 2.6.32-504.el6.x86_64 #1 SMP Tue Sep 16 01:56:35 EDT 2014 x86_64 x86_64 x86_64 GNU/Linux

      A DESCRIPTION OF THE PROBLEM :
      the implementation of InflaterInputStream.available():

         public int available() throws IOException {
              ensureOpen();
              if (reachEOF) {
                  return 0;
              } else {
                  return 1;
              }
          }

      will return 1 in situations where the underlying inflater is actually finished, but has not been read() from (so no -1 seen). it seems that the condition in the method can be updated to :

         public int available() throws IOException {
              ensureOpen();
              if (reachEOF || inf.finished()) {
                  return 0;
              } else {
                  return 1;
              }
          }

      such that available() will return 0 correctly (instead of returning available = 1 and the subsequent read() returning -1).

      the impact of this is that if such an inflater stream is wrapped in a DataInputStream, the following code cannot work:

      InflaterStream underlying = ...;
      DataInsputStream decorator = ... //wrap underlying
      while (underlying.available() > 0) {
         //read something via decorator
      }

      with the current code the only option is to catch an EOF (thrown by DataInputStream in response to reading -1 as part of readFully())

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      the following code will reproduce the issue:

          public static void main(String[] args) throws Exception {
              ByteArrayOutputStream baos = new ByteArrayOutputStream();
              GZIPOutputStream zos = new GZIPOutputStream(baos);
              zos.write("some content".getBytes(Charset.forName("UTF-8")));
              zos.close();
              byte[] zippedBlob = baos.toByteArray();
              GZIPInputStream zis = new GZIPInputStream(new ByteArrayInputStream(zippedBlob));
              while (zis.available() > 0) {
                  int read = zis.read();
                  if (read == -1) {
                      System.err.println("you lied to me");
                  }
              }
          }

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      code should run with nothing printed to system.err
      ACTUAL -
      message printed to System.err indicating available() returned a positive value yet the subsequent read() returned -1

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
          public static void main(String[] args) throws Exception {
              ByteArrayOutputStream baos = new ByteArrayOutputStream();
              GZIPOutputStream zos = new GZIPOutputStream(baos);
              zos.write("some content".getBytes(Charset.forName("UTF-8")));
              zos.close();
              byte[] zippedBlob = baos.toByteArray();
              GZIPInputStream zis = new GZIPInputStream(new ByteArrayInputStream(zippedBlob));
              while (zis.available() > 0) {
                  int read = zis.read();
                  if (read == -1) {
                      System.err.println("you lied to me");
                  }
              }
          }
      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      forced to catch the EOFException throws by DataInputStream in response to -1. this has a performance impact on my code.

            chegar Chris Hegarty
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: