From 8cbf8ecc07c1739a7f1d27c7a36517c1397b3cc6 Mon Sep 17 00:00:00 2001 From: Elliotte Rusty Harold Date: Wed, 1 Jul 2026 10:42:05 -0400 Subject: [PATCH 1/2] Close process streams after exit to work around JDK-4311711 hang --- .../shared/utils/cli/CommandLineUtils.java | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/main/java/org/apache/maven/shared/utils/cli/CommandLineUtils.java b/src/main/java/org/apache/maven/shared/utils/cli/CommandLineUtils.java index 5c0307c5..33a183da 100644 --- a/src/main/java/org/apache/maven/shared/utils/cli/CommandLineUtils.java +++ b/src/main/java/org/apache/maven/shared/utils/cli/CommandLineUtils.java @@ -18,6 +18,7 @@ */ package org.apache.maven.shared.utils.cli; +import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; import java.util.ArrayList; @@ -274,27 +275,26 @@ public Integer call() throws CommandLineException { int returnValue = p.waitFor(); - // TODO Find out if waitUntilDone needs to be called using a try-finally construct. The method may - // throw an - // InterruptedException so that calls to waitUntilDone may be skipped. - // try - // { - // if ( inputFeeder != null ) - // { - // inputFeeder.waitUntilDone(); - // } - // } - // finally - // { - // try - // { - // outputPumper.waitUntilDone(); - // } - // finally - // { - // errorPumper.waitUntilDone(); - // } - // } + // Close the process streams to work around JDK-4311711: + // Process.getInputStream().read() can hang indefinitely + // even after the process has terminated. Closing the + // streams causes the pumpers' readLine() calls to return. + try { + p.getOutputStream().close(); + } catch (IOException e) { + // ignore + } + try { + p.getInputStream().close(); + } catch (IOException e) { + // ignore + } + try { + p.getErrorStream().close(); + } catch (IOException e) { + // ignore + } + if (inputFeeder != null) { inputFeeder.waitUntilDone(); } From 6e24d4e0d2008887ddada55fde0973add61d5814 Mon Sep 17 00:00:00 2001 From: Elliotte Rusty Harold Date: Mon, 3 Aug 2026 11:49:45 +0000 Subject: [PATCH 2/2] Make waitUntilDone(long) package-private like isDone() and isDisabled() --- .../apache/maven/shared/utils/cli/AbstractStreamHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/apache/maven/shared/utils/cli/AbstractStreamHandler.java b/src/main/java/org/apache/maven/shared/utils/cli/AbstractStreamHandler.java index 804bdf49..ae12d7f4 100644 --- a/src/main/java/org/apache/maven/shared/utils/cli/AbstractStreamHandler.java +++ b/src/main/java/org/apache/maven/shared/utils/cli/AbstractStreamHandler.java @@ -45,7 +45,7 @@ public synchronized void waitUntilDone() throws InterruptedException { * @return {@code true} if the handler finished within the timeout, {@code false} otherwise * @throws InterruptedException if the current thread is interrupted while waiting */ - public synchronized boolean waitUntilDone(long timeoutInMillis) throws InterruptedException { + synchronized boolean waitUntilDone(long timeoutInMillis) throws InterruptedException { if (timeoutInMillis <= 0) { waitUntilDone(); return true;