On Tue, 13 Jan 2026 16:52:36 GMT, Ioi Lam <[email protected]> wrote:
> The bug is here on line 121:
>
> https://github.com/openjdk/jdk/blob/586846b84a38d285c5905437e903cfc57f609410/src/java.base/windows/classes/java/lang/ProcessImpl.java#L118-L121
>
> 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/src/java.base/windows/native/libjava/ProcessImpl_md.c#L158-L184
>
> 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