JDK-4850368 : (process) getInputStream() attaches to forked background processes (Linux)
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang
  • Affected Version: 1.4.1_02,1.4.2
  • Priority: P3
  • Status: Closed
  • Resolution: Duplicate
  • OS: linux
  • CPU: x86
  • Submitted: 2003-04-17
  • Updated: 2003-04-22
  • Resolved: 2003-04-22
Related Reports
Duplicate :  
Description

Name: nt126004			Date: 04/17/2003


FULL PRODUCT VERSION :
java version "1.4.1_01"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1_01-b01)
Java HotSpot(TM) Client VM (build 1.4.1_01-b01, mixed mode)

and 

java version "1.4.2-rc"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.2-rc-b20)
Java HotSpot(TM) Client VM (build 1.4.2-rc-b20, mixed mode)


FULL OS VERSION :
Linux 7ctadev01 2.4.7-10 #1 Thu Sep 6 17:27:27 EDT 2001 i686 unknown

A DESCRIPTION OF THE PROBLEM :
When using Runtime.exec() to run a shell script that spawns background processes, reads against the InputStream that is returned by Process.getInputStream() will block until the spawned process dies, even if that process is launched in the background and it's output is redirected.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
[root@7ctadev01 tmp]# cat test.sh
#!/bin/sh
echo "Launching sleep script now"
sleep 10 1>/dev/null 2>&1 &
echo "Done launching sleep script now"

[root@7ctadev01 tmp]# /usr/java/jdk1.3.1_02/bin/java Exec ./test.sh
stdout : Launching sleep script now
stdout : Done launching sleep script now
Done reading standard output
It took 35 milliseconds to read output

[root@7ctadev01 tmp]# /usr/java/j2sdk1.4.1_01/bin/java Exec ./test.sh
stdout : Launching sleep script now
stdout : Done launching sleep script now
Done reading standard output
It took 10043 milliseconds to read output


EXPECTED VERSUS ACTUAL BEHAVIOR :
The run with jdk 1.4.1 should have completed before the process spawned by the test.sh script ended, as the run with jdk 1.3.1 did.  The timing was added to the code in an effort to prove that the Exec program was trying to read the output from the spawned process.

REPRODUCIBILITY :
This bug can be reproduced always.

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

public class Exec {

    public static void main(String[] args) {

        String command = "";
        for (int i = 0; i < args.length; i++) {
            command += args[i];

            if (i != args.length) command += " ";
        }

        try {
            long startTime = System.currentTimeMillis();

            Process process = Runtime.getRuntime().exec(command);

            BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));

            String line = null;
            while ((line = br.readLine()) != null) {
                System.out.println("stdout : " + line);
            }

            System.out.println("Done reading standard output");

            System.out.println("It took " + (System.currentTimeMillis() - startTime)
                + " milliseconds to read output");

        } catch(Exception e) {
            e.printStackTrace();
        }
    }
}

---------- END SOURCE ----------
(Review ID: 183327) 
======================================================================

Comments
PUBLIC COMMENTS Reads from the input stream of an exec'ed process do not always get an EOF at the appropriate time because not all file descriptors are correctly closed. Will be fixed when 4843136 is fixed.
10-06-2004

EVALUATION I have reproduced this on Linux, but not on Solaris. On Linux, I have reproduced it with the current development versions of 1.5 and 1.4.2, as well as 1.4.1_02. This appears to be the old "file descriptors not being closed in the child" bug, which has resisted fixing efforts, but appears to finally be fixed as a result of the pending fix to 4843136 (process) pipe file descriptor from Runtime.exec not being closed I have verified that my not-yet-integrated patch for this bug in fact causes the reported problem to go away. The reported test case is very interesting because it is good for reproducing this bug on Linux. Test cases I have developed independently seem to be more reproducible on multi-CPU solaris than on uni-CPU Linux. Here's what seems to be happening: After the fork, the child calls (UNIXProcess_md.c.linux) dup2(fdout[1], 1); to create the stdout for the about-to-be-execed process. Unfortunately, fdout[1] is not explicitly closed, and the bug in closeDescriptors (4843136) prevents that descriptor from being closed since the parent closes that descriptor immediately. The child in turn execs another process with stdout redirected, but the grandchild inherits that fdout[1] descriptor, preventing the grandparent from getting EOF on process.getInputStream(). This particular test case doesn't show up on Solaris since UNIXProcess_md.c.solaris explicitly closes fdout[1]. These kinds of subtle differences between Solaris and Linux should be eliminated eventually when 4790606 (process) Native forkAndExec code should be unified (sol, lnx) is addressed. ###@###.### 2003-04-22
22-04-2003