JDK-4103432 : (process) "Exec"ed processes hang on NT when reading the standard input
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang
  • Affected Version: 1.1.5,1.1.6,1.2.2
  • Priority: P5
  • Status: Closed
  • Resolution: Won't Fix
  • OS: windows_nt
  • CPU: x86
  • Submitted: 1998-01-12
  • Updated: 2007-07-13
  • Resolved: 2007-07-13
Related Reports
Relates :  
Relates :  
Relates :  
Relates :  
Description
Name: joT67522			Date: 01/12/98

On Windows NT, closing the "input" stream of a
subprocess doesn't work as expected. That is, if 
I "exec" a command that tries to read from the 
standard input till the end-of-stream, 
it will hang. For instance,

class test {
  public static void main (String [] args) {
    try {
      Process proc = Runtime.getRuntime().exec("cat");
      proc.getOutputStream().close();
      proc.waitFor();
    }
      catch (Exception e) { System.out.println("Exception"); }
  }
}

The "close" goes unnoticed by the "exec"ed 
process. I have tried this with several commands
(some that I wrote and compiled myself and some
system commands). Every command that tries to
read from the standard input hangs (doesn't get
an end-of-stream notification). 

Identical source code runs fine on Solaris (both
on Sparcstations and x86). I have not tried it
under Windows 95.

I also tried writing explicitly an end-of-file
character (-1) to the stream, with no luck.

This is an important problem (for me, that is :-).
It means I cannot "exec" an application in binary
format which reads data from the standard input.
(Review ID: 22647)
======================================================================

Here is another test case submitted via the web which sends the output 
of exec("ls -ls") to the input of "cat".  On Solaris it works great,
but on NT it hangs trying to read the output of the "cat" Process.
brian.klock@eng 1998-06-18

//----------------------proc_io.java-------------------------
import java.io.*;
public class proc_io {
	public static void main(String args[]) throws IOException {
		Process proc1 = Runtime.getRuntime().exec("ls -ls");
		Process proc2 = Runtime.getRuntime().exec("sort");
		// What state is proc2 in right now?  Is it waiting for input, or has it finished?

		BufferedReader proc1StdOut = new BufferedReader(new InputStreamReader(proc1.getInputStream()));
		BufferedReader proc2StdOut = new BufferedReader(new InputStreamReader(proc2.getInputStream()));
		PrintWriter proc2StdIn = new PrintWriter(proc2.getOutputStream());
		String line1StdOut;
		String line2StdOut;

		// copy stdout from proc1 to stdin on proc2
		while( true ) {
			line1StdOut=proc1StdOut.readLine();
			if( line1StdOut==null )
				break;
			proc2StdIn.println(line1StdOut);
			proc2StdIn.flush();
		}

                proc2StdIn.close();

		// dump stdout on proc2 to screen
		while( true ) {
			// next line goobers in java.io.FileInputStream.read(byte b[]) which calls readBytes(byte[], int, int)
			line2StdOut=proc2StdOut.readLine();
			if( line2StdOut==null )
				break;
			System.out.println( line2StdOut );
		}
		proc1.destroy();
		proc2.destroy();
	}
}

======================================================================



Name: mc57594			Date: 11/11/99


Under certain circumstances, the input stream of a Process created by Runtime.exec() (obtained from Process.getInputStream()) never indicates end-of-file, even though the process runs to completion. Therefore the exec'ing process, which is copying the stream, hangs waiting for more stream data.

I'm running the latest JDK 1.2.2. This problem happens both with HotSpot and with the classic JVM. It happens under Windows 98 (the 2nd edition release) and Windows NT4 (sp5). My test input and output are very small, so I'm sure blocking due to buffer overflow is not an issue.

Version info:

>java -version
java version "1.2.2"
HotSpot VM (1.0.1, mixed mode, build g)

>java -fullversion
java full version "JDK-1.2.2-W"

>java -classic -version
java version "1.2.2"
Classic VM (build JDK-1.2.2-W, native threads, symcjit)

>java -classic -fullversion
java full version "JDK-1.2.2-W"

The circumstances, as best I can figure out, are that both of the following must be true:

  - The process being run by Runtime.exec() is "java" (it does
    not seem to hang for non-java processes).
  - The process reads from standard input.

I have some small test programs that can reproduce this -- I'll include them after this text. They are:

run.java -- a very simple program to run another process. It
            takes an optional -i <input file> option, and passes
            remaining arguments as a String[] to exec().
cp.java -- a program to copy standard input to standard output
out.java -- a program to print a short message (reads no input)

Running:

    java run -i hello.txt java cp

hangs up. (hello.txt is a file with contents "Hello.\n".) The exec'd cp.java process completes its loop that reads standard input, sends all of its standard output, and the process presumably terminates. However, run.java never completes its loop to copy the process's output.

The interesting thing is that this only seems to happen when exec'ing a "java" process. A similar "cp" program created most any other way works fine. It seems that the JVM is not doing something at process completion that "normal" processes do.

Also, if the java process does not read from standard input, it works okay. Using the out.java program:

    java run java out

works okay. Also:

    java run -i hello.txt java out

works okay too, so even though it tries to send data to the exec'd process's standard input, things terminate normally as long as the exec'd process does not actually _read_ from standard input.

By the way, (yeah I know I'm supposed to focus on one problem) on DOS only (not NT), the run.java process has to send a ^Z character at the end of its input, otherwise the exec'd cp.java process does not detect end-of-file on its input!

Here are my little test programs:

////////// run.java

import java.io.*;

class run {

	public static void main(String[] args) throws Exception {
		//
		// Create an input stream if -i option.
		//
		String inputFile = null;
		if (args[0].equals("-i")) {
			inputFile = args[1];
			String[] newArgs = new String[args.length - 2];
			System.arraycopy(args, 2, newArgs, 0, args.length - 2);
			args = newArgs;
		}
		//
		// Start a process using command line arguments as the String
		// array passed to Runtime.exec().
		//
		Process p = Runtime.getRuntime().exec(args);
		int c;
		//
		// If an input file specified, copy input to the process.
		//
		if (inputFile != null) {
			FileInputStream in = new FileInputStream(inputFile);
			while ((c = in.read()) >= 0) {
				System.out.println("in: '" + (char)c + '\'');
				p.getOutputStream().write(c);
			}
			System.out.println("in: Done.");
			//p.getOutputStream().write('\u001a'); // ^Z
			p.getOutputStream().flush();
		}
		//
		// Copy output from process.
		//
		while ((c = p.getInputStream().read()) >= 0) {
			System.out.println("out: '" + (char)c + '\'');
			//System.out.write(c);
		}
		System.out.println("out: Done.");
		//
		// Wait for process to complete.
		//
		p.waitFor();
		System.out.println("process: Done.");
	}

}


////// cp.java

class cp {

	public static void main(String[] args) throws Exception {
		int c;
		while ((c = System.in.read()) >= 0) {
			System.out.write(c);
		}
		System.out.println("Done.");
	}

}


///////// out.java

class out {

	public static void main(String[] args) {
		System.out.println("Out.");
	}

}
(Review ID: 94279)
======================================================================

Comments
EVALUATION Friday the 13th is a good day for this long-suffering bug to die.
13-07-2007

EVALUATION I took another look at this bug. I used a variant of the submitter's program public class Bug { public static void main (String[] args) throws Throwable { Process proc = Runtime.getRuntime().exec("cat"); proc.getOutputStream().close(); int n = proc.waitFor(); if (n != 0) throw new Error(""+n); } } On Windows 2000, this hangs on JDK 1.1.6 - 1.1.8, but works fine on JDK 1.2+ The JDK (and Microsoft!) no longer support Win98 or Windows NT, and I no longer have a Win98 test machine around, and no one knows the underlying cause or has a fix. Is it time to close this bug?
08-07-2007

EVALUATION This is the intended behavior ever since the original design of Process. The parent process must feed stdin to the subprocess. The current API does not support creating a subprocess which has it own console or other kind of stdio redirection. See javadoc in Process.java ###@###.### 1998-02-15 As for the second test case, the win32 behavior is correct, the Solaris behavior is just bogus. That is only because we create additional threads to pump the io stream from child process in order to save file disriptor on Solaris. Look at the recent javadoc in Process.java, if the parent process does not pump the output from child process, the child will block when pipe is full. This is the intended behavior. ###@###.### 1998-06-18 There seem to be two different issues here. The program "test" should work on all with all of our implementations. In fact, I have tried it on Windows 2000, for all versions from 1.2.2 to 1.5.0, and cannot reproduce the problem. Perhaps we've fixed it? If so, we should close it not reproducible. As for the second problem...one can expect proc_io to hang, depending on the size of the data and the system pipe buffers. This is a standard gotcha. It can be avoided by having one thread to read from "ls -l" and write to "sort", and another thread to read from "sort". Consider this extract from "man perlfunc" pipe READHANDLE,WRITEHANDLE Opens a pair of connected pipes like the corresponding system call. Note that if you set up a loop of piped processes, deadlock can occur unless you are very careful. This issue should be closed "not a bug". ###@###.### 2003-09-12 ================================ The evaulator states tthat the program "test" should work. So it seems this bug report shouldn't be closed as "not a bug" since the original and main focus of the bug report is the program "test" and that is still reproducible with JDK 1.5 beta2 (build 43) on Windows 98/SE. It hangs there. But as the previous evaluator notes, it exits properly on Windows 2000 and XP. This bug was the cause of 5007388 which also manifests only on windows 9X. ###@###.### 2004-03-29 ============================
29-03-2004

WORK AROUND Name: joT67522 Date: 01/12/98 Partial workarounds: Obviously, if one has access to the source code for the "exec"ed application, one can change it to read its input from a file. Alternatively, the application could expect a pattern other than the end-of-stream and finish processing when it detects it. A different solution would be to write a routine in C or to use a shell with indirection. This is far from platform-independent, though. ====================================================================== Obviously, the other workaround is to create a separate thread to run the exec'd application. Then the parent thread could monitor the progress of the stream. The method available() could be called to determine if more data exists, otherwise the stream reading is done. mark.chamness@Eng 1999-11-11
11-11-1999