JDK-5101298 : (process) "IOException: Stream closed" if more data sent after Process.destroy
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang
  • Affected Version: 1.4.2
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • OS: linux
  • CPU: x86
  • Submitted: 2004-09-13
  • Updated: 2024-04-12
Description
Name: gm110360			Date: 09/13/2004


FULL PRODUCT VERSION :
java version "1.5.0-rc"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0-rc-b63)
Java HotSpot(TM) Client VM (build 1.5.0-rc-b63, mixed mode, sharing)

ADDITIONAL OS VERSION INFORMATION :
Linux melanie 2.4.9-e.12smp #1 SMP Tue Feb 11 02:24:10 EST 2003 i686 unknown (Red Hat Enterprise Edition)
Also happens on SuSE Linux 8.1 with Kernel 2.6.7

A DESCRIPTION OF THE PROBLEM :
While reading stdout of a native process, an "IOException: Stream closed" is thrown if the process writes some more characters to stdout after Process.destroy() has been called. It is not possible to read until the end of the stream.
If a process does not write any data to stdout at the moment Process.destroy() is called, the exception is not thrown.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Please place the class "ProcessTest" and the shell script "sigtrap.sh" in a directory and execute the class.
It should execute the shell script for 3 sec, read its stdout and print it to the console, and then terminate the process by calling destroy().

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
I would expect the class to print three lines read from stdout of the script and  then the line "trapped SIGTERM".
This actually happens on HP-UX 11.11 (with Java version 1.4.0).
ACTUAL -
Instead of printing "trapped SIGTERM", an "IOException: Stream closed" is thrown. If line 7 in sigtrap.sh is commented out, no data will be written to stdout by the process when it is terminated, and the exception will not occur.

This is what I think what happens: When destroy() is called on a Process,  its input, output and error streams are closed immediately, so that it is not possible to read until the end of the streams without getting an IOException. If the streams are empty at the moment where the process is destroyed, the exception does not occur because the end of the stream(s) was reached before they are closed.

ERROR MESSAGES/STACK TRACES THAT OCCUR :
Process stdout: Waiting for signal...0
Process stdout: Waiting for signal...1
Process stdout: Waiting for signal...2
java.io.IOException: Stream closed
        at java.io.BufferedInputStream.getBufIfOpen(BufferedInputStream.java:145)
        at java.io.BufferedInputStream.read1(BufferedInputStream.java:253)
        at java.io.BufferedInputStream.read(BufferedInputStream.java:313)
        at sun.nio.cs.StreamDecoder$CharsetSD.readBytes(StreamDecoder.java:411)
        at sun.nio.cs.StreamDecoder$CharsetSD.implRead(StreamDecoder.java:453)
        at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:183)
        at java.io.InputStreamReader.read(InputStreamReader.java:167)
        at java.io.BufferedReader.fill(BufferedReader.java:136)
        at java.io.BufferedReader.readLine(BufferedReader.java:299)
        at java.io.BufferedReader.readLine(BufferedReader.java:362)
        at ProcessTest$1.run(ProcessTest.java:19)

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
=== BEGIN ProcessTest.java ===
import java.io.*;

public class ProcessTest {

  public static void main(String[] args) {
    Process p = null;
    try {
      p = Runtime.getRuntime().exec("./sigtrap.sh");
    }
    catch(IOException ioe) {
      ioe.printStackTrace();
    }

    final BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));

    Thread t = new Thread() {
      public void run() {
        try {
          for(String line = null; (line = br.readLine()) != null;) {
            System.out.println("Process stdout: " + line);
          }
        }
        catch(IOException ioe) {
          ioe.printStackTrace();
        }
      }
    };
    t.start();

    try {
      Thread.sleep(3000);
    }
    catch(Exception e) {}
    p.destroy();
  }
}
=== END ProcessTest.java ===

=== BEGIN sigtrap.sh ===
#!/bin/bash
# sigtrap.sh

trap trappedTerm 15

function trappedTerm {
  echo "trapped SIGTERM"
  exit
}

COUNTER=0;
while(true)
  do
  echo "Waiting for signal...$COUNTER" | tee -a out.txt
  sleep 1
  let COUNTER=$COUNTER+1
done
=== END sigtrap.sh ===
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
I have not found a workaround. I am not even sure if this actually is a bug or just a user error. But as this problem does not occur on HP-UX (and maybe also other UNIXes), I think it might be a bug.

Release Regression From : 1.4.2
The above release value was the last known release where this 
bug was known to work. Since then there has been a regression.

(Incident Review ID: 305485) 
======================================================================

Comments
EVALUATION Handling of proper and prompt cleanup of OS resources is in general a hard problem, and particularly so in the Process handling code. Other users have complained about file handles not being closed promptly enough, causing exhaustion of such OS resources.
07-10-2005