RFR: 8366736: Closed System.out causes child process to hang on Windows
The bug is here on line 121: https://github.com/openjdk/jdk/blob/586846b84a38d285c5905437e903cfc57f609410... If `System.out` has been closed, `fdAccess.getHandle()` will return -1. This causes `stdHandles[1]` to have the same value as if the child process's stdout was redirected with `Redirect.PIPE`. This will cause a Pipe to be created here for the child process's STDOUT on line 168: https://github.com/openjdk/jdk/blob/586846b84a38d285c5905437e903cfc57f609410... However, the caller of the `ProcessBuilder` is not aware of this and will not drain this pipe. This causes the child process to get stuck when writing to its stdout when the pipe 's buffer is filled up. The fix is to treat the redirection as `Redirect.DISCARD` when `System.out` and/or `System.err` have been closed. ------------- Commit messages: - 8366736: Closed System.out causes child process to hang on Windows Changes: https://git.openjdk.org/jdk/pull/29198/files Webrev: https://webrevs.openjdk.org/?repo=jdk&pr=29198&range=00 Issue: https://bugs.openjdk.org/browse/JDK-8366736 Stats: 105 lines in 2 files changed: 100 ins; 0 del; 5 mod Patch: https://git.openjdk.org/jdk/pull/29198.diff Fetch: git fetch https://git.openjdk.org/jdk.git pull/29198/head:pull/29198 PR: https://git.openjdk.org/jdk/pull/29198
On Tue, 13 Jan 2026 16:52:36 GMT, Ioi Lam <iklam@openjdk.org> wrote:
The bug is here on line 121:
https://github.com/openjdk/jdk/blob/586846b84a38d285c5905437e903cfc57f609410...
If `System.out` has been closed, `fdAccess.getHandle()` will return -1. This causes `stdHandles[1]` to have the same value as if the child process's stdout was redirected with `Redirect.PIPE`. This will cause a Pipe to be created here for the child process's STDOUT on line 168:
https://github.com/openjdk/jdk/blob/586846b84a38d285c5905437e903cfc57f609410...
However, the caller of the `ProcessBuilder` is not aware of this and will not drain this pipe. This causes the child process to get stuck when writing to its stdout when the pipe 's buffer is filled up.
The fix is to treat the redirection as `Redirect.DISCARD` when `System.out` and/or `System.err` have been closed.
The bug is here on line 121:
https://github.com/openjdk/jdk/blob/586846b84a38d285c5905437e903cfc57f609410...
If `System.out` has been closed, `fdAccess.getHandle()` will return -1. This causes `stdHandles[1]` to have the same value as if the child process's stdout was redirected with `Redirect.PIPE`. This will cause a Pipe to be created here for the child process's STDOUT on line 168:
https://github.com/openjdk/jdk/blob/586846b84a38d285c5905437e903cfc57f609410...
However, the caller of the `ProcessBuilder` is not aware of this and will not drain this pipe. This causes the child process to get stuck when writing to its stdout after the pipe 's buffer is filled up.
The fix is to treat the redirection as `Redirect.DISCARD` when `System.out` and/or `System.err` have been closed.
### Progress * [ ] Change must be properly reviewed (1 review required, with at least 1 [Reviewer](https://openjdk.org/bylaws#reviewer)) * [x] Change must not contain extraneous whitespace * [x] Commit message must refer to an issue
### Issue * [JDK-8366736](https://bugs.openjdk.org/browse/JDK-8366736): Closed System.out causes child process to hang on Windows (**Bug** - P4)
### Reviewing Using `git` Checkout this PR locally: `$ git fetch https://git.openjdk.org/jdk.git pull/29198/head:pull/29198` `$ git checkout pull/29198`
Update a local copy of the PR: `$ git checkout pull/29198` `$ git pull https://git.openjdk.org/jdk.git pull/29198/head`
Using Skara CLI tools Checkout this PR locally: `$ git pr checkout 29198`
View PR using the GUI difftool: `$ git pr show -t 29198`
Using diff file
------------- PR Comment: https://git.openjdk.org/jdk/pull/29198#issuecomment-3745764159
On Tue, 13 Jan 2026 16:52:36 GMT, Ioi Lam <iklam@openjdk.org> wrote:
The bug is here on line 121:
https://github.com/openjdk/jdk/blob/586846b84a38d285c5905437e903cfc57f609410...
If `System.out` has been closed, `fdAccess.getHandle()` will return -1. This causes `stdHandles[1]` to have the same value as if the child process's stdout was redirected with `Redirect.PIPE`. This will cause a Pipe to be created here for the child process's STDOUT on line 168:
https://github.com/openjdk/jdk/blob/586846b84a38d285c5905437e903cfc57f609410...
However, the caller of the `ProcessBuilder` is not aware of this and will not drain this pipe. This causes the child process to get stuck when writing to its stdout when the pipe 's buffer is filled up.
The fix is to treat the redirection as `Redirect.DISCARD` when `System.out` and/or `System.err` have been closed.
src/java.base/windows/classes/java/lang/ProcessImpl.java line 118:
116: } 117: 118: Redirect file1 = null;
Remove src/java.base/windows/classes/java/lang/ProcessImpl.java line 125:
123: if (stdHandles[1] == -1L) { 124: // FileDescriptor.out has been closed. 125: file1 = Redirect.DISCARD;
Suggestion: // FileDescriptor.out has been closed. f1 = newFileOutputStream(Redirect.DISCARD.file(), Redirect.DISCARD.append()); stdHandles[1] = fdAccess.getHandle(f1.getFD()); Inline the change and avoid extra local state variable src/java.base/windows/classes/java/lang/ProcessImpl.java line 137:
135: if (file1 != null) { 136: f1 = newFileOutputStream(file1.file(), 137: file1.append());
Revert to original. src/java.base/windows/classes/java/lang/ProcessImpl.java line 141:
139: } 140: 141: Redirect file2 = null;
Remove src/java.base/windows/classes/java/lang/ProcessImpl.java line 148:
146: if (stdHandles[2] == -1L) { 147: // FileDescriptor.err has been closed. 148: file2 = Redirect.DISCARD;
Suggestion: // FileDescriptor.err has been closed. f2 = newFileOutputStream(Redirect.DISCARD.file(), Redirect.DISCARD.append()); stdHandles[2] = fdAccess.getHandle(f2.getFD()); Inline the change to discard stderr. src/java.base/windows/classes/java/lang/ProcessImpl.java line 157:
155: if (file2 != null) { 156: f2 = newFileOutputStream(file2.file(), 157: file2.append());
Revert to original. test/jdk/java/lang/ProcessBuilder/InheritIOClosed.java line 52:
50: "1234567890" + 51: "1234567890" + 52: "1234567890";
Suggestion: private final static Path JAVA_EXE = Path.of(System.getProperty("java.home"), "bin", "java"); private static final String s = "1234567890".repeat(10); Path is more compact. test/jdk/java/lang/ProcessBuilder/InheritIOClosed.java line 65:
63: 64: ProcessBuilder pb = new ProcessBuilder().inheritIO() 65: .command(JAVA_EXE,
Suggestion: .command(JAVA_EXE.toString(), ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/29198#discussion_r2687961657 PR Review Comment: https://git.openjdk.org/jdk/pull/29198#discussion_r2687960154 PR Review Comment: https://git.openjdk.org/jdk/pull/29198#discussion_r2687961222 PR Review Comment: https://git.openjdk.org/jdk/pull/29198#discussion_r2687965150 PR Review Comment: https://git.openjdk.org/jdk/pull/29198#discussion_r2687964194 PR Review Comment: https://git.openjdk.org/jdk/pull/29198#discussion_r2687964792 PR Review Comment: https://git.openjdk.org/jdk/pull/29198#discussion_r2687982258 PR Review Comment: https://git.openjdk.org/jdk/pull/29198#discussion_r2687984357
On Tue, 13 Jan 2026 20:04:49 GMT, Roger Riggs <rriggs@openjdk.org> wrote:
Ioi Lam has updated the pull request incrementally with one additional commit since the last revision:
Review comments from @RogerRiggs
src/java.base/windows/classes/java/lang/ProcessImpl.java line 125:
123: if (stdHandles[1] == -1L) { 124: // FileDescriptor.out has been closed. 125: file1 = Redirect.DISCARD;
Suggestion:
// FileDescriptor.out has been closed. f1 = newFileOutputStream(Redirect.DISCARD.file(), Redirect.DISCARD.append()); stdHandles[1] = fdAccess.getHandle(f1.getFD());
Inline the change and avoid extra local state variable
To avoid cut-and-pasting the same code 4 times, I refactored the code into a separate function, `setFileOutput()`.
test/jdk/java/lang/ProcessBuilder/InheritIOClosed.java line 52:
50: "1234567890" + 51: "1234567890" + 52: "1234567890";
Suggestion:
private final static Path JAVA_EXE = Path.of(System.getProperty("java.home"), "bin", "java");
private static final String s = "1234567890".repeat(10);
Path is more compact.
Fixed as suggested. ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/29198#discussion_r2688783638 PR Review Comment: https://git.openjdk.org/jdk/pull/29198#discussion_r2688784628
The bug is here on line 121:
https://github.com/openjdk/jdk/blob/586846b84a38d285c5905437e903cfc57f609410...
If `System.out` has been closed, `fdAccess.getHandle()` will return -1. This causes `stdHandles[1]` to have the same value as if the child process's stdout was redirected with `Redirect.PIPE`. This will cause a Pipe to be created here for the child process's STDOUT on line 168:
https://github.com/openjdk/jdk/blob/586846b84a38d285c5905437e903cfc57f609410...
However, the caller of the `ProcessBuilder` is not aware of this and will not drain this pipe. This causes the child process to get stuck when writing to its stdout when the pipe 's buffer is filled up.
The fix is to treat the redirection as `Redirect.DISCARD` when `System.out` and/or `System.err` have been closed.
Ioi Lam has updated the pull request incrementally with one additional commit since the last revision: Review comments from @RogerRiggs ------------- Changes: - all: https://git.openjdk.org/jdk/pull/29198/files - new: https://git.openjdk.org/jdk/pull/29198/files/30b312e1..e9006f5e Webrevs: - full: https://webrevs.openjdk.org/?repo=jdk&pr=29198&range=01 - incr: https://webrevs.openjdk.org/?repo=jdk&pr=29198&range=00-01 Stats: 43 lines in 2 files changed: 9 ins; 25 del; 9 mod Patch: https://git.openjdk.org/jdk/pull/29198.diff Fetch: git fetch https://git.openjdk.org/jdk.git pull/29198/head:pull/29198 PR: https://git.openjdk.org/jdk/pull/29198
On Wed, 14 Jan 2026 03:22:33 GMT, Ioi Lam <iklam@openjdk.org> wrote:
The bug is here on line 121:
https://github.com/openjdk/jdk/blob/586846b84a38d285c5905437e903cfc57f609410...
If `System.out` has been closed, `fdAccess.getHandle()` will return -1. This causes `stdHandles[1]` to have the same value as if the child process's stdout was redirected with `Redirect.PIPE`. This will cause a Pipe to be created here for the child process's STDOUT on line 168:
https://github.com/openjdk/jdk/blob/586846b84a38d285c5905437e903cfc57f609410...
However, the caller of the `ProcessBuilder` is not aware of this and will not drain this pipe. This causes the child process to get stuck when writing to its stdout when the pipe 's buffer is filled up.
The fix is to treat the redirection as `Redirect.DISCARD` when `System.out` and/or `System.err` have been closed.
Ioi Lam has updated the pull request incrementally with one additional commit since the last revision:
Review comments from @RogerRiggs
I think this is an okay approach but it is inherently racy, and this is on top of the issues with async close of the streams. ------------- PR Comment: https://git.openjdk.org/jdk/pull/29198#issuecomment-3748981061
On Wed, 14 Jan 2026 03:22:33 GMT, Ioi Lam <iklam@openjdk.org> wrote:
The bug is here on line 121:
https://github.com/openjdk/jdk/blob/586846b84a38d285c5905437e903cfc57f609410...
If `System.out` has been closed, `fdAccess.getHandle()` will return -1. This causes `stdHandles[1]` to have the same value as if the child process's stdout was redirected with `Redirect.PIPE`. This will cause a Pipe to be created here for the child process's STDOUT on line 168:
https://github.com/openjdk/jdk/blob/586846b84a38d285c5905437e903cfc57f609410...
However, the caller of the `ProcessBuilder` is not aware of this and will not drain this pipe. This causes the child process to get stuck when writing to its stdout when the pipe 's buffer is filled up.
The fix is to treat the redirection as `Redirect.DISCARD` when `System.out` and/or `System.err` have been closed.
Ioi Lam has updated the pull request incrementally with one additional commit since the last revision:
Review comments from @RogerRiggs
src/java.base/windows/classes/java/lang/ProcessImpl.java line 133:
131: if (stdHandles[1] == -1L) { 132: // FileDescriptor.out has been closed. 133: f1 = setFileOutput(Redirect.DISCARD, stdHandles, 1);
More compact yes, but I prefer to update local state inline, its easier to see the consistent pattern of state updates across the different cases. ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/29198#discussion_r2690701865
On Wed, 14 Jan 2026 03:22:33 GMT, Ioi Lam <iklam@openjdk.org> wrote:
The bug is here on line 121:
https://github.com/openjdk/jdk/blob/586846b84a38d285c5905437e903cfc57f609410...
If `System.out` has been closed, `fdAccess.getHandle()` will return -1. This causes `stdHandles[1]` to have the same value as if the child process's stdout was redirected with `Redirect.PIPE`. This will cause a Pipe to be created here for the child process's STDOUT on line 168:
https://github.com/openjdk/jdk/blob/586846b84a38d285c5905437e903cfc57f609410...
However, the caller of the `ProcessBuilder` is not aware of this and will not drain this pipe. This causes the child process to get stuck when writing to its stdout when the pipe 's buffer is filled up.
The fix is to treat the redirection as `Redirect.DISCARD` when `System.out` and/or `System.err` have been closed.
Ioi Lam has updated the pull request incrementally with one additional commit since the last revision:
Review comments from @RogerRiggs
The change in behavior should be documented in an APINote on Process.inheritIO() to say that the output is discarded if it has been closed. ------------- PR Comment: https://git.openjdk.org/jdk/pull/29198#issuecomment-3749879254
On Wed, 14 Jan 2026 14:40:04 GMT, Roger Riggs <rriggs@openjdk.org> wrote:
The change in behavior should be documented in an APINote on Process.inheritIO() to say that the output is discarded if it has been closed.
I added an APINote for `Process.inheritIO()`: * @apiNote * If {#code System.out} and/or {#code System.err} have been * closed in the current process, the corresponding output * in the subprocess will be discarded.
src/java.base/windows/classes/java/lang/ProcessImpl.java line 133:
131: if (stdHandles[1] == -1L) { 132: // FileDescriptor.out has been closed. 133: f1 = setFileOutput(Redirect.DISCARD, stdHandles, 1);
More compact yes, but I prefer to update local state inline, its easier to see the consistent pattern of state updates across the different cases.
I updated the code as you suggested. ------------- PR Comment: https://git.openjdk.org/jdk/pull/29198#issuecomment-3769993899 PR Review Comment: https://git.openjdk.org/jdk/pull/29198#discussion_r2705980676
On Wed, 14 Jan 2026 14:40:04 GMT, Roger Riggs <rriggs@openjdk.org> wrote:
Ioi Lam has updated the pull request incrementally with one additional commit since the last revision:
Review comments from @RogerRiggs
The change in behavior should be documented in an APINote on Process.inheritIO() to say that the output is discarded if it has been closed.
Thank you @RogerRiggs @AlanBateman for your review ------------- PR Comment: https://git.openjdk.org/jdk/pull/29198#issuecomment-3910383520
The bug is here on line 121:
https://github.com/openjdk/jdk/blob/586846b84a38d285c5905437e903cfc57f609410...
If `System.out` has been closed, `fdAccess.getHandle()` will return -1. This causes `stdHandles[1]` to have the same value as if the child process's stdout was redirected with `Redirect.PIPE`. This will cause a Pipe to be created here for the child process's STDOUT on line 168:
https://github.com/openjdk/jdk/blob/586846b84a38d285c5905437e903cfc57f609410...
However, the caller of the `ProcessBuilder` is not aware of this and will not drain this pipe. This causes the child process to get stuck when writing to its stdout when the pipe 's buffer is filled up.
The fix is to treat the redirection as `Redirect.DISCARD` when `System.out` and/or `System.err` have been closed.
Ioi Lam has updated the pull request incrementally with two additional commits since the last revision: - Reverted previous unintended commit - 8375654: Exclude all array classes from dynamic CDS archive ------------- Changes: - all: https://git.openjdk.org/jdk/pull/29198/files - new: https://git.openjdk.org/jdk/pull/29198/files/e9006f5e..6ef4a4da Webrevs: - full: https://webrevs.openjdk.org/?repo=jdk&pr=29198&range=02 - incr: https://webrevs.openjdk.org/?repo=jdk&pr=29198&range=01-02 Stats: 0 lines in 0 files changed: 0 ins; 0 del; 0 mod Patch: https://git.openjdk.org/jdk/pull/29198.diff Fetch: git fetch https://git.openjdk.org/jdk.git pull/29198/head:pull/29198 PR: https://git.openjdk.org/jdk/pull/29198
The bug is here on line 121:
https://github.com/openjdk/jdk/blob/586846b84a38d285c5905437e903cfc57f609410...
If `System.out` has been closed, `fdAccess.getHandle()` will return -1. This causes `stdHandles[1]` to have the same value as if the child process's stdout was redirected with `Redirect.PIPE`. This will cause a Pipe to be created here for the child process's STDOUT on line 168:
https://github.com/openjdk/jdk/blob/586846b84a38d285c5905437e903cfc57f609410...
However, the caller of the `ProcessBuilder` is not aware of this and will not drain this pipe. This causes the child process to get stuck when writing to its stdout when the pipe 's buffer is filled up.
The fix is to treat the redirection as `Redirect.DISCARD` when `System.out` and/or `System.err` have been closed.
Ioi Lam has updated the pull request with a new target base due to a merge or a rebase. The incremental webrev excludes the unrelated changes brought in by the merge/rebase. The pull request contains seven additional commits since the last revision: - fixed typo - Merge branch 'master' into 8366736-closed-system-out-causes-child-process-to-hang-on-windows - Review comments from @RogerRiggs - Reverted previous unintended commit - 8375654: Exclude all array classes from dynamic CDS archive - Review comments from @RogerRiggs - 8366736: Closed System.out causes child process to hang on Windows ------------- Changes: - all: https://git.openjdk.org/jdk/pull/29198/files - new: https://git.openjdk.org/jdk/pull/29198/files/6ef4a4da..7785fde1 Webrevs: - full: https://webrevs.openjdk.org/?repo=jdk&pr=29198&range=03 - incr: https://webrevs.openjdk.org/?repo=jdk&pr=29198&range=02-03 Stats: 26705 lines in 491 files changed: 14871 ins; 6166 del; 5668 mod Patch: https://git.openjdk.org/jdk/pull/29198.diff Fetch: git fetch https://git.openjdk.org/jdk.git pull/29198/head:pull/29198 PR: https://git.openjdk.org/jdk/pull/29198
The bug is here on line 121:
https://github.com/openjdk/jdk/blob/586846b84a38d285c5905437e903cfc57f609410...
If `System.out` has been closed, `fdAccess.getHandle()` will return -1. This causes `stdHandles[1]` to have the same value as if the child process's stdout was redirected with `Redirect.PIPE`. This will cause a Pipe to be created here for the child process's STDOUT on line 168:
https://github.com/openjdk/jdk/blob/586846b84a38d285c5905437e903cfc57f609410...
However, the caller of the `ProcessBuilder` is not aware of this and will not drain this pipe. This causes the child process to get stuck when writing to its stdout when the pipe 's buffer is filled up.
The fix is to treat the redirection as `Redirect.DISCARD` when `System.out` and/or `System.err` have been closed.
Ioi Lam has updated the pull request incrementally with one additional commit since the last revision: Fixed typo ------------- Changes: - all: https://git.openjdk.org/jdk/pull/29198/files - new: https://git.openjdk.org/jdk/pull/29198/files/7785fde1..4b7d30c0 Webrevs: - full: https://webrevs.openjdk.org/?repo=jdk&pr=29198&range=04 - incr: https://webrevs.openjdk.org/?repo=jdk&pr=29198&range=03-04 Stats: 1 line in 1 file changed: 0 ins; 0 del; 1 mod Patch: https://git.openjdk.org/jdk/pull/29198.diff Fetch: git fetch https://git.openjdk.org/jdk.git pull/29198/head:pull/29198 PR: https://git.openjdk.org/jdk/pull/29198
On Mon, 19 Jan 2026 21:47:26 GMT, Ioi Lam <iklam@openjdk.org> wrote:
The bug is here on line 121:
https://github.com/openjdk/jdk/blob/586846b84a38d285c5905437e903cfc57f609410...
If `System.out` has been closed, `fdAccess.getHandle()` will return -1. This causes `stdHandles[1]` to have the same value as if the child process's stdout was redirected with `Redirect.PIPE`. This will cause a Pipe to be created here for the child process's STDOUT on line 168:
https://github.com/openjdk/jdk/blob/586846b84a38d285c5905437e903cfc57f609410...
However, the caller of the `ProcessBuilder` is not aware of this and will not drain this pipe. This causes the child process to get stuck when writing to its stdout when the pipe 's buffer is filled up.
The fix is to treat the redirection as `Redirect.DISCARD` when `System.out` and/or `System.err` have been closed.
Ioi Lam has updated the pull request incrementally with one additional commit since the last revision:
Fixed typo
The APINote will trigger need for a CSR. src/java.base/share/classes/java/lang/ProcessBuilder.java line 936:
934: * If {#code System.out} and/or {#code System.err} have been 935: * closed in the current process, the corresponding output 936: * in the subprocess will be discarded.
Suggestion: * When the process is {@link #start started}, * if {#code System.out} and/or {#code System.err} have been * closed in the current process, the corresponding output * in the subprocess will be discarded. Qualified to apply at the time the process is started, not when ProcessBuilder.inheritIO is called. ------------- PR Review: https://git.openjdk.org/jdk/pull/29198#pullrequestreview-3708036042 PR Review Comment: https://git.openjdk.org/jdk/pull/29198#discussion_r2729282389
On Mon, 26 Jan 2026 21:15:55 GMT, Roger Riggs <rriggs@openjdk.org> wrote:
Ioi Lam has updated the pull request incrementally with one additional commit since the last revision:
Fixed typo
src/java.base/share/classes/java/lang/ProcessBuilder.java line 936:
934: * If {#code System.out} and/or {#code System.err} have been 935: * closed in the current process, the corresponding output 936: * in the subprocess will be discarded.
Suggestion:
* When the process is {@link #start started}, * if {#code System.out} and/or {#code System.err} have been * closed in the current process, the corresponding output * in the subprocess will be discarded.
Qualified to apply at the time the process is started, not when ProcessBuilder.inheritIO is called.
Thank Roger. I updated the text as you suggested and create the CSR: [JDK-8376413](https://bugs.openjdk.org/browse/JDK-8376413) ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/29198#discussion_r2729403602
On Mon, 26 Jan 2026 21:53:59 GMT, Ioi Lam <iklam@openjdk.org> wrote:
src/java.base/share/classes/java/lang/ProcessBuilder.java line 936:
934: * If {#code System.out} and/or {#code System.err} have been 935: * closed in the current process, the corresponding output 936: * in the subprocess will be discarded.
Suggestion:
* When the process is {@link #start started}, * if {#code System.out} and/or {#code System.err} have been * closed in the current process, the corresponding output * in the subprocess will be discarded.
Qualified to apply at the time the process is started, not when ProcessBuilder.inheritIO is called.
Thank Roger. I updated the text as you suggested and create the CSR: [JDK-8376413](https://bugs.openjdk.org/browse/JDK-8376413)
API notes provide "commentary, rationale, or examples pertaining to the API". They don't strictly require a CSR as they aren't spec. I think the proposed note is closer to an implNote as it is documenting what the JDK implementation does if the out/error streams are closed. We could potentially consider promoting it to spec, requiring all implementations to discard in this case, maybe you've discussed this already? ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/29198#discussion_r2730733839
On Tue, 27 Jan 2026 08:02:38 GMT, Alan Bateman <alanb@openjdk.org> wrote:
Thank Roger. I updated the text as you suggested and create the CSR: [JDK-8376413](https://bugs.openjdk.org/browse/JDK-8376413)
API notes provide "commentary, rationale, or examples pertaining to the API". They don't strictly require a CSR as they aren't spec.
I think the proposed note is closer to an implNote as it is documenting what the JDK implementation does if the out/error streams are closed. We could potentially consider promoting it to spec, requiring all implementations to discard in this case, maybe you've discussed this already?
I changed it to use `@implNote` ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/29198#discussion_r2808604835
The bug is here on line 121:
https://github.com/openjdk/jdk/blob/586846b84a38d285c5905437e903cfc57f609410...
If `System.out` has been closed, `fdAccess.getHandle()` will return -1. This causes `stdHandles[1]` to have the same value as if the child process's stdout was redirected with `Redirect.PIPE`. This will cause a Pipe to be created here for the child process's STDOUT on line 168:
https://github.com/openjdk/jdk/blob/586846b84a38d285c5905437e903cfc57f609410...
However, the caller of the `ProcessBuilder` is not aware of this and will not drain this pipe. This causes the child process to get stuck when writing to its stdout when the pipe 's buffer is filled up.
The fix is to treat the redirection as `Redirect.DISCARD` when `System.out` and/or `System.err` have been closed.
Ioi Lam has updated the pull request incrementally with one additional commit since the last revision: @RogerRiggs review comments ------------- Changes: - all: https://git.openjdk.org/jdk/pull/29198/files - new: https://git.openjdk.org/jdk/pull/29198/files/4b7d30c0..6210d8b2 Webrevs: - full: https://webrevs.openjdk.org/?repo=jdk&pr=29198&range=05 - incr: https://webrevs.openjdk.org/?repo=jdk&pr=29198&range=04-05 Stats: 2 lines in 1 file changed: 1 ins; 0 del; 1 mod Patch: https://git.openjdk.org/jdk/pull/29198.diff Fetch: git fetch https://git.openjdk.org/jdk.git pull/29198/head:pull/29198 PR: https://git.openjdk.org/jdk/pull/29198
On Mon, 26 Jan 2026 21:49:52 GMT, Ioi Lam <iklam@openjdk.org> wrote:
The bug is here on line 121:
https://github.com/openjdk/jdk/blob/586846b84a38d285c5905437e903cfc57f609410...
If `System.out` has been closed, `fdAccess.getHandle()` will return -1. This causes `stdHandles[1]` to have the same value as if the child process's stdout was redirected with `Redirect.PIPE`. This will cause a Pipe to be created here for the child process's STDOUT on line 168:
https://github.com/openjdk/jdk/blob/586846b84a38d285c5905437e903cfc57f609410...
However, the caller of the `ProcessBuilder` is not aware of this and will not drain this pipe. This causes the child process to get stuck when writing to its stdout when the pipe 's buffer is filled up.
The fix is to treat the redirection as `Redirect.DISCARD` when `System.out` and/or `System.err` have been closed.
Ioi Lam has updated the pull request incrementally with one additional commit since the last revision:
@RogerRiggs review comments
Thanks for the updates. ------------- Marked as reviewed by rriggs (Reviewer). PR Review: https://git.openjdk.org/jdk/pull/29198#pullrequestreview-3708363428
The bug is here on line 121:
https://github.com/openjdk/jdk/blob/586846b84a38d285c5905437e903cfc57f609410...
If `System.out` has been closed, `fdAccess.getHandle()` will return -1. This causes `stdHandles[1]` to have the same value as if the child process's stdout was redirected with `Redirect.PIPE`. This will cause a Pipe to be created here for the child process's STDOUT on line 168:
https://github.com/openjdk/jdk/blob/586846b84a38d285c5905437e903cfc57f609410...
However, the caller of the `ProcessBuilder` is not aware of this and will not drain this pipe. This causes the child process to get stuck when writing to its stdout when the pipe 's buffer is filled up.
The fix is to treat the redirection as `Redirect.DISCARD` when `System.out` and/or `System.err` have been closed.
Ioi Lam has updated the pull request with a new target base due to a merge or a rebase. The incremental webrev excludes the unrelated changes brought in by the merge/rebase. The pull request contains 11 additional commits since the last revision: - Review comment by @AlanBateman: use implNote instead. Also fixed whitespaces - Merge branch 'master' into 8366736-closed-system-out-causes-child-process-to-hang-on-windows - @RogerRiggs review comments - Fixed typo - fixed typo - Merge branch 'master' into 8366736-closed-system-out-causes-child-process-to-hang-on-windows - Review comments from @RogerRiggs - Reverted previous unintended commit - 8375654: Exclude all array classes from dynamic CDS archive - Review comments from @RogerRiggs - ... and 1 more: https://git.openjdk.org/jdk/compare/46ecfee8...bc999867 ------------- Changes: - all: https://git.openjdk.org/jdk/pull/29198/files - new: https://git.openjdk.org/jdk/pull/29198/files/6210d8b2..bc999867 Webrevs: - full: https://webrevs.openjdk.org/?repo=jdk&pr=29198&range=06 - incr: https://webrevs.openjdk.org/?repo=jdk&pr=29198&range=05-06 Stats: 105676 lines in 1961 files changed: 50340 ins; 24875 del; 30461 mod Patch: https://git.openjdk.org/jdk/pull/29198.diff Fetch: git fetch https://git.openjdk.org/jdk.git pull/29198/head:pull/29198 PR: https://git.openjdk.org/jdk/pull/29198
On Sun, 15 Feb 2026 06:01:02 GMT, Ioi Lam <iklam@openjdk.org> wrote:
The bug is here on line 121:
https://github.com/openjdk/jdk/blob/586846b84a38d285c5905437e903cfc57f609410...
If `System.out` has been closed, `fdAccess.getHandle()` will return -1. This causes `stdHandles[1]` to have the same value as if the child process's stdout was redirected with `Redirect.PIPE`. This will cause a Pipe to be created here for the child process's STDOUT on line 168:
https://github.com/openjdk/jdk/blob/586846b84a38d285c5905437e903cfc57f609410...
However, the caller of the `ProcessBuilder` is not aware of this and will not drain this pipe. This causes the child process to get stuck when writing to its stdout when the pipe 's buffer is filled up.
The fix is to treat the redirection as `Redirect.DISCARD` when `System.out` and/or `System.err` have been closed.
Ioi Lam has updated the pull request with a new target base due to a merge or a rebase. The incremental webrev excludes the unrelated changes brought in by the merge/rebase. The pull request contains 11 additional commits since the last revision:
- Review comment by @AlanBateman: use implNote instead. Also fixed whitespaces - Merge branch 'master' into 8366736-closed-system-out-causes-child-process-to-hang-on-windows - @RogerRiggs review comments - Fixed typo - fixed typo - Merge branch 'master' into 8366736-closed-system-out-causes-child-process-to-hang-on-windows - Review comments from @RogerRiggs - Reverted previous unintended commit - 8375654: Exclude all array classes from dynamic CDS archive - Review comments from @RogerRiggs - ... and 1 more: https://git.openjdk.org/jdk/compare/6d00da44...bc999867
Looks good. ------------- Marked as reviewed by rriggs (Reviewer). PR Review: https://git.openjdk.org/jdk/pull/29198#pullrequestreview-3805643832
On Sun, 15 Feb 2026 06:01:02 GMT, Ioi Lam <iklam@openjdk.org> wrote:
The bug is here on line 121:
https://github.com/openjdk/jdk/blob/586846b84a38d285c5905437e903cfc57f609410...
If `System.out` has been closed, `fdAccess.getHandle()` will return -1. This causes `stdHandles[1]` to have the same value as if the child process's stdout was redirected with `Redirect.PIPE`. This will cause a Pipe to be created here for the child process's STDOUT on line 168:
https://github.com/openjdk/jdk/blob/586846b84a38d285c5905437e903cfc57f609410...
However, the caller of the `ProcessBuilder` is not aware of this and will not drain this pipe. This causes the child process to get stuck when writing to its stdout when the pipe 's buffer is filled up.
The fix is to treat the redirection as `Redirect.DISCARD` when `System.out` and/or `System.err` have been closed.
Ioi Lam has updated the pull request with a new target base due to a merge or a rebase. The incremental webrev excludes the unrelated changes brought in by the merge/rebase. The pull request contains 11 additional commits since the last revision:
- Review comment by @AlanBateman: use implNote instead. Also fixed whitespaces - Merge branch 'master' into 8366736-closed-system-out-causes-child-process-to-hang-on-windows - @RogerRiggs review comments - Fixed typo - fixed typo - Merge branch 'master' into 8366736-closed-system-out-causes-child-process-to-hang-on-windows - Review comments from @RogerRiggs - Reverted previous unintended commit - 8375654: Exclude all array classes from dynamic CDS archive - Review comments from @RogerRiggs - ... and 1 more: https://git.openjdk.org/jdk/compare/f3eaab4c...bc999867
src/java.base/share/classes/java/lang/ProcessBuilder.java line 935:
933: * @implNote 934: * When the process is {@link #start started}, 935: * if {#code System.out} and/or {#code System.err} have been
Thanks for moving it to an implNote. For word smithing, It might be better to say "and System.out and/or System.err has been closed". Also it would be better to say the current VM rather than the current process here as these APIs relate to the current VM. ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/29198#discussion_r2815168712
On Tue, 13 Jan 2026 16:52:36 GMT, Ioi Lam <iklam@openjdk.org> wrote:
The bug is here on line 121:
https://github.com/openjdk/jdk/blob/586846b84a38d285c5905437e903cfc57f609410...
If `System.out` has been closed, `fdAccess.getHandle()` will return -1. This causes `stdHandles[1]` to have the same value as if the child process's stdout was redirected with `Redirect.PIPE`. This will cause a Pipe to be created here for the child process's STDOUT on line 168:
https://github.com/openjdk/jdk/blob/586846b84a38d285c5905437e903cfc57f609410...
However, the caller of the `ProcessBuilder` is not aware of this and will not drain this pipe. This causes the child process to get stuck when writing to its stdout when the pipe 's buffer is filled up.
The fix is to treat the redirection as `Redirect.DISCARD` when `System.out` and/or `System.err` have been closed.
This pull request has now been integrated. Changeset: c3b67387 Author: Ioi Lam <iklam@openjdk.org> URL: https://git.openjdk.org/jdk/commit/c3b67387c4c0891891c75f9001ba13feaae09017 Stats: 91 lines in 3 files changed: 89 ins; 0 del; 2 mod 8366736: Closed System.out causes child process to hang on Windows Reviewed-by: rriggs ------------- PR: https://git.openjdk.org/jdk/pull/29198
participants (3)
-
Alan Bateman
-
Ioi Lam
-
Roger Riggs