JDK-1266819 : The java.io.PipedInputStream.read() method works wrong when writer thread dies
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang
  • Affected Version: 1.0.2
  • Priority: P1
  • Status: Closed
  • Resolution: Not an Issue
  • OS: solaris_2.5
  • CPU: sparc
  • Submitted: 1996-09-06
  • Updated: 2021-11-09
  • Resolved: 1996-09-12
Related Reports
Relates :  
Description

Name: saf@russia			Date: 09/06/96


This bug was found by St.Petersburg Java SQE team (by Stanislav Avzan).

The java.io.PipedInputStream.read() method does not work according to 
the Java language specification when writer thread is no longer alive.

The Java Language specification 
(Version 1.0 - August 1, 1996)
says the following (please see item 22.5.4):

"22.5.4 public int read() throws IOException 

If a thread was providing data bytes to the connected piped output
stream, but the thread is no longer alive, then an IOException is thrown. 

Implements the read method of InputStream (p.22.3.1)."

So this method should throw IOException
if writer thread is no longer alive.
But in fact it does not.
 
Here is the test demonstrating the bug:
    

----- test6.java ---------------------------------------
import java.io.*;

public class test6 {

  public static void main( String[] argv ) {
    PipedOutputStream os = new PipedOutputStream(); 
    PipedInputStream is= new PipedInputStream();
    Producer p;
    int rl;
    try {
      is.connect(os); 
     } catch(Throwable e) {
       System.out.println("Test failed: unexpected <"+e+"> thrown");
       System.exit(1); 
     } 
    byte[] data = new byte[1000], comp = new byte[1000]; // create  two arrays of bytes
    try {
       p = new Producer(data,os,"Test");// create Producer thread using this array
      p.start();// start producing bytes of data
      try {
        Thread.sleep(1000); // sleep for 1 second
      } catch (InterruptedException e) {}
      p.stop(); //step stop producer thread
      System.out.println("Is producer alive? - "+p.isAlive());
      rl = is.read(comp,0,1000); // read into  array of bytes
      System.out.println("Test failed: no exceptions thrown"); 
    }
    catch(IOException e) // test IOException is thrown
    { System.out.println("Test passed: IOException thrown");   
    } catch(Throwable e) {
      System.out.println("Test failed: unexpected <"+e+"> thrown"); 
    } 
  }
}
------- Producer.java ---------------------------------
import java.io.*;

class Producer extends Thread {
  private byte[] data;
  private PipedOutputStream src;
  private String testid;
  private int delay;

  public Producer(byte[] data, PipedOutputStream src, String testid) {
    this.data = data;
    this.src = src;
    this.testid = testid;
    this.delay = 0;
  }
  
  public Producer(byte[] data, PipedOutputStream src, String testid, int delay) {
    this.data = data;
    this.src = src;
    this.testid = testid;
    this.delay = delay;
  }

  public void run() {
    for (int i=0; i < data.length; i++)
      try {
        if (delay > 0)
          try {
            Thread.sleep(delay);
          } catch (InterruptedException e) {}  
        src.write(data[i]);
      } catch (IOException e) {
        System.out.println(testid + " failed: PipedOutputStream write error");
        System.exit(1);
      }
    try {
      if (delay > 0)
        try {
          Thread.sleep(delay);
        } catch (InterruptedException e) {}  
      src.close();
      sleep(10000); //  to allow reader read all written
    } catch(InterruptedException e) {
      } catch (IOException e) {
        System.out.println(testid + " failed: PipedOutputStream close error");
        System.exit(1);
      }    
  }      

}

----- The output of the test: -------------------------

$JAVA test6
Is producer alive? - false
Test failed: no exceptions thrown

-------------------------------------------------------


Workaround:
None
======================================================================

Comments
EVALUATION I think the spec is wrong in this case. Even if the writer thread has died, there's no reason not to allow the reader to finish reading the pipe. Further, throwing IOException is inappropriate. Simply returning EOF when nothing is left and the reader is dead is appropriate, and the code presently does this. I've recommended to jag that the spec be changed to reflect this. -brown
11-06-2004