Skip to content

Commit f013c85

Browse files
committed
fix(exec): 消除 stdin 管道竞态——执行器总是向子进程提供(可能为空的)即时关闭 stdin;替身脚本先排空 stdin 再回显
- CI 实证(JDK 8 + Ubuntu):commons-exec 泵入 stdin 时,不读 stdin 的 快退进程会触发 write-after-close(exit=-1,stderr=Stream closed), 1.4.0 必现、1.6.0 仍抖动 - 修复后:消费型命令(codex login --with-api-key)读满载荷到 EOF; 不消费的命令拿到立即 EOF 的空管道,泵不再有迟到写入 - 副作用说明:子进程 stdin 从"挂起管道"变为"关闭管道",对非交互 SDK 是更严格正确的语义
1 parent 433b9c7 commit f013c85

2 files changed

Lines changed: 10 additions & 6 deletions

File tree

src/main/java/io/github/easy4j/codex/cli/CodexCliExecutor.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -120,12 +120,12 @@ private CodexCliResult runProcess(String stdin, String... args) {
120120
DefaultExecutor executor = new DefaultExecutor();
121121
ByteArrayOutputStream stdout = new ByteArrayOutputStream();
122122
ByteArrayOutputStream stderr = new ByteArrayOutputStream();
123-
if (stdin != null && !stdin.isEmpty()) {
124-
executor.setStreamHandler(new org.apache.commons.exec.PumpStreamHandler(stdout, stderr,
125-
new ByteArrayInputStream(stdin.getBytes(StandardCharsets.UTF_8))));
126-
} else {
127-
executor.setStreamHandler(new org.apache.commons.exec.PumpStreamHandler(stdout, stderr));
128-
}
123+
// Always hand the child a (possibly empty) stdin pipe that closes
124+
// right after the payload: consumers like `codex login --with-api-key`
125+
// read to EOF, and a closed pipe cannot race the input pump.
126+
byte[] stdinBytes = stdin == null ? new byte[0] : stdin.getBytes(StandardCharsets.UTF_8);
127+
executor.setStreamHandler(new org.apache.commons.exec.PumpStreamHandler(stdout, stderr,
128+
new ByteArrayInputStream(stdinBytes)));
129129

130130
long timeoutMs = config.getLocalTimeoutSeconds() * 1000L;
131131
ExecuteWatchdog watchdog = new ExecuteWatchdog(timeoutMs);

src/test/resources/echo-args.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,8 @@
66
# coreutils echo (Linux) interprets --version/--help as flags while BSD echo
77
# (macOS) prints them literally.
88
#
9+
# Drain piped stdin first: real `codex login --with-api-key` consumes its
10+
# stdin payload; reading to EOF also keeps the executor's input pump race-free
11+
# (an immediately-closed pipe yields instant EOF here).
12+
cat > /dev/null 2>/dev/null
913
printf '%s\n' "$*"

0 commit comments

Comments
 (0)