From 4c41b562c07c20c6df03d0cda3e28bda3295ffba Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Thu, 29 Jan 2026 08:02:09 +0000 Subject: ash: don't skip exec() if std streams are invalid This didn't produce the expected output when run from ash: ash -c "echo abc | sed s/a/x/" <&- In general, if the last command in the pipe read from stdin the command didn't work; if it read from file descriptor 0 (e.g. cat) it did. Closing a file descriptor caused the corresponding stream to become invalid. For performance reasons the shell in busybox-w32 runs applets without an exec(), but that results in their seeing the invalid stream from their parent. Avoid the problem by calling exec() in such cases. This causes the child process to get a new stdin stream initialised from the file descriptor. The test also applies to stdout and stderr. There's no discernable affect on performance when running the test suite. Adds 64-96 bytes. (GitHub issue #558) --- shell/ash.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'shell') diff --git a/shell/ash.c b/shell/ash.c index 330de607f..90e9168be 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -9318,7 +9318,9 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, c /* Treat all applets as NOEXEC, including the shell itself * if we were called from forkshell_shellexec(). */ run_noexec: - if (applet_main[applet_no] != ash_main || noexec) { + if ((applet_main[applet_no] != ash_main || noexec) && + fileno(stdin) != -2 && fileno(stdout) != -2 && + fileno(stderr) != -2) { /* mingw-w64's getopt() uses __argv[0] as the program name */ __argv[0] = (char *)cmd; /* 'which' wants to know if it was invoked from a standalone -- cgit v1.2.3-55-g6feb