JDK-4763384 : (process) Intermittent hang on piped input (lnx)
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang
  • Affected Version: 1.4.1
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: linux
  • CPU: x86
  • Submitted: 2002-10-15
  • Updated: 2002-12-17
  • Resolved: 2002-12-17
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
1.4.2 b11Fixed
Related Reports
Relates :  
Relates :  
Description

Name: rmT116609			Date: 10/15/2002


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


FULL OPERATING SYSTEM VERSION :
Linux kernel 2.2.14-6.1.1, also seen on 2.2.16 glibc-2.1.3-26



A DESCRIPTION OF THE PROBLEM :
When using Runtime.exec in java1.4.1 on an external program
that needs to read standard input, the program will hang on
a pipe read about 50% of the time.  Under 1.4, this never
occurred.  Since the external program never consumes its
input, it never exits or performs its work and thus
Process.waitFor will hang.

REGRESSION.  Last worked in version 1.4

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. compile the attached test program (client JVM)
2. run repeatedly under java1.4.1
3. should hang within a few runs and hang about 50% time
overall.

EXPECTED VERSUS ACTUAL BEHAVIOR :
When the program is working correctly (java 1.4,
java1.3.1), it will print the exit code and then exit.
When it is failing it will hang with no exit code printed.

ERROR MESSAGES/STACK TRACES THAT OCCUR :
No error message.   Program hangs.

REPRODUCIBILITY :
This bug can be reproduced often.

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

/**
 * This class demonstrates a regression in java1.4.1 in the handling of
 * the Process OutputStream (exec'd process stdin).   main executes
 * to completion 100% of the time in java1.4, but about only about 50%
 * of the time under 1.4.1.  Issue exists for client JVM, Linux Redhat 6.2
 * not sure about other variants of Linux or other Os, or server JVM.
 */
public class ExecRegression
{
    private static final String CAT = "/bin/cat";

    public static void main(String[] args)
    {
      /*
       * Execute /bin/cat supplying two lines of input.  cat should
       * read the input lines and copy them to stdout.  On completion,
       * p.waitFor should return and the exit status is printed and this
       * program exits.  Under 1.4.1, cat sometimes gets stuck on a pipe
       * read and never terminates.
       */
      try {
        Process p = Runtime.getRuntime().exec(new String[] { CAT } );
        String input = "This is Line 1\nThis is Line 2\n";
        StringBufferInputStream in = new StringBufferInputStream(input);
        // create threads to handle I/O streams
        IO ioIn = new IO("stdin", in, p.getOutputStream());
        IO ioOut = new IO("stdout", p.getInputStream(), System.out);
        IO ioErr = new IO("stderr", p.getErrorStream(), System.err);

        // wait for process to exit
        int status = p.waitFor();
        System.out.println(status);
        System.exit(status);
     } catch (Exception e) {
        e.printStackTrace();
     }
    }

    private ExecRegression() {}

    /**
     * Handle IO.  Thread is started in constructor.
     */
    static class IO extends Thread {

        private InputStream in;
        private OutputStream out;

        IO(String name, InputStream in, OutputStream out)
        {
            this.in = in;
            this.out = out;
            setName(name);
            start();
        }

        public void run() {
            try {
                int c;
                while ((c = in.read()) != -1) {
                    out.write(c);
                }
                out.flush();
            } catch (IOException e) {
            } finally {
                if (!System.out.equals(out) && !System.err.equals(out)) {
                    // Note: in order to get an exec'd java process to
                    // see EOF on input, it is necessary to close stdin
                    if (out != null)
                        try { out.close(); } catch (Exception e) {}
                }
            }
        }
    }
}


---------- END SOURCE ----------


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

(Review ID: 165706) 
======================================================================

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: mantis-beta FIXED IN: mantis-beta INTEGRATED IN: mantis-b11 mantis-beta
14-06-2004

SUGGESTED FIX *** /tmp/geta22066 Tue Dec 3 05:07:15 2002 --- UNIXProcess_md.c.linux Tue Dec 3 05:07:14 2002 *************** *** 375,380 **** --- 375,389 ---- dup2(fderr[1], 2); /* close everything */ + + /* We can't rely upon the kernel to have updated /proc/pid/fd with the + * parent's most-recently-opened descriptors by the time we get here, + * so we explicitly close the parent's sides of the in/out/err pipes. + */ + close(fdin[1]); + close(fdout[0]); + close(fderr[0]); + if (closeDescriptors() == 0) { /* failed, close the old way */ max_fd = (int)sysconf(_SC_OPEN_MAX); for (i = 3; i < max_fd; i++) close(i);
11-06-2004

EVALUATION Fairly easy to reproduce using latest 1.4.2 build. -- ###@###.### 2002/12/2 Another case of /proc/pid/fd not being atomically updated by the kernel. The closeDescriptors() procedure in UNIXProcess_md.c.linux doesn't always see all of the descriptors for the parent's sides of the in/out/err pipes. This is easy to work around: We simply to close these three descriptors explicitly before calling closeDescriptors() to close the rest. This regression from 1.4.0 should be fixed in 1.4.2 since it affects stability. The fix is simple and safe. -- ###@###.### 2002/12/3 There was a deeper underlying bug that was fixed in 4843136 (process) pipe file descriptor from Runtime.exec not being closed ###@###.### 2003-04-27
12-10-0169

WORK AROUND Sleep for a very small amount of time (1ms seems to work) immediately after starting the subprocess, e.g., Process p = Runtime.getRuntime().exec(CAT); Thread.sleep(1); ... -- ###@###.### 2002/12/2
12-10-0168