JDK-8167651 : InflaterInputStream.available() returns 1 even when underlying Inflater is finished
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.util.jar
  • Affected Version: 8
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2016-10-12
  • Updated: 2017-01-02
  • Resolved: 2017-01-02
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 8
8-poolFixed
Related Reports
Duplicate :  
Duplicate :  
Description
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.


Comments
To reproduce the issue, run the attached test case. Following were the results on the various JDK versions: JDK 8 - Fail JDK 8u102 - Fail JDK 8u122ea - Fail JDK 9ea +137 - Pass Following are the outputs with the failed and passed versions: JDK 8 & 8uxx --------------------- >java -showversion JI9044476 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) you lied to me JDK 9ea +137 ------------------------- >java -showversion JI9044476 java version "9-ea" Java(TM) SE Runtime Environment (build 9-ea+137) Java HotSpot(TM) 64-Bit Server VM (build 9-ea+137, mixed mode) ------------------------------- This is fixed in JDK 9 with JDK-7031075.
13-10-2016