JDK-4291371 : InputStreamReader.read(char[], int, int) loops if stream read() returns zero
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.io
  • Affected Version: 1.2.2
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: generic
  • CPU: generic
  • Submitted: 1999-11-15
  • Updated: 2002-05-23
  • Resolved: 2002-05-23
Related Reports
Duplicate :  
Description

Name: mc57594			Date: 11/15/99


/*

I'm using JDK 1.2.2 on Windows 98.  I create an InputStreamReader() to
read from a stream, converting the bytes to chars.  I specify a
character set of ISO8859_1 (though I don't think that's significant).
If I call the InputStreamReader.read(char[] int, int) method, and the
stream's read(byte[]) method returns zero, the call to
InputStreamReader() never returns, looping infinitely attempting to
read from the stream.

Just so you know, the stream that I'm reading from is one returned
from SerialPort.getInputSteam(), from the Window's implementation of
the Java Communication API.  It sometimes returns zero because I've
established a timeout using the CommPort.enableReceiveTimeout()
method.  If no data is available after blocking for the given amount
of time, the stream's read(byte[]) call returns zero.

The looping code is actually in the InputStreamReader.fill() method.
The first call to the stream's read(byte[]) method returns zero.  The
subsequent call to InputStreamReader.convertInto() returns zero, so
the "nc" variable remains equal to zero.  This causes the subsequent
trip through the loop to conclude that it hasn't yet blocked on a call
to the stream's read(byte[]) method.  But in fact it has blocked, in
my case of the length of time specified by the established timeout.

As an aside, I observe the following inconsistency: The input stream
returned by java.lang.Socket throws a java.io.InterruptedIOException
if a read from the stream times out.  A socket read can be made to
time out by calling Socket.setSoTimeout().  But the stream returned by
CommPort.getInputStream() simply returns zero, without throwing an
exception.  The documentation for InputStream.read(byte[]) doesn't
indicate that zero is an invalid value, though.  Hmmm, I've just
noticed this sentence in the InputStream.read(byte[]) description:
"This method blocks until input data is available, end of file is
detected, or an exception is thrown."  I suppose this could be
interpreted to indicate that a zero return value will never occur.

At any rate, here's a small sample program to demonstrate the problem.
It requires the Java Communication API to run.  It wraps the Serial
port's stream with one that prints a line when a call is made to the
stream's read(byte[]) method.  This makes it easy to see that
InputStreamReader.fill() is looping.

To run this program, it is not necessary to connect anything to the
serial port, since the read is supposed to time out anyway.

*/
import java.io.*;
import javax.comm.*;

class InputReaderBug {
    public static void main(String[] args)
        throws Exception
    {
        CommPortIdentifier id = CommPortIdentifier.getPortIdentifier("COM1");

        SerialPort port = (SerialPort) id.open("Test program", 10000);

        port.enableReceiveTimeout(3000);

        InputStream stream = new VocalInputStream(port.getInputStream());
        Reader input = new InputStreamReader(stream, "ISO8859_1");

        char[] buf = new char[80];

        System.out.println("Calling InputStreamReader.read(char[])");
        int cnt = input.read(buf);
        System.out.println("InputStreamReader.read(char[]) returned value of " + cnt);
    }
}

class VocalInputStream extends FilterInputStream {
    public VocalInputStream (InputStream in) {
        super(in);
    }

    public int read(byte b[])
        throws IOException
    {
        System.out.println("Call to stream's read(byte[])");
        int c = super.read(b);
        System.out.println("Stream read " + c + " bytes");
        return c;
    }
}
(Review ID: 96854) 
======================================================================

Comments
WORK AROUND Name: mc57594 Date: 11/15/99 My workaround will be to implement my own input stream reader, simply putting a high-order zero byte on each read byte to create a char. My converter will handle a return value of zero from the stream. ======================================================================
11-06-2004

EVALUATION The problem is that InputStream has no built in notion of timeouts. It can only block indefinitely, return -1 for end of stream, or throw an exception. Since timing out is different than end of stream, I'm surprised the CommPort.getInputStream impl doesn't throw some kind of TimeoutException. Will investigate further. ###@###.### 2002-05-16
16-05-2002