From 6b164f335c548bcebacd8bf984fd5c34ede46891 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Tue, 30 Apr 2024 09:08:00 +0100 Subject: ash: fix alias expansion followed by '&' An alias expansion immediately followed by '&' is parsed incorrectly: ~ $ alias x='sleep 2' ~ $ x& ~ $ sh: syntax error: unexpected "&" The sleep happens in the foreground and the '&' is left in the input buffer. The same problem occurs in upstream BusyBox but not dash. The difference between BusyBox and dash is that BusyBox supports bash-style output redirection (BASH_REDIR_OUTPUT in the code). This requires checking for '&>' in readtoken1(). When the end of the alias is found, the '&' and the following newline are both read to check for '&>'. Since there's no match both characters are pushed back. The alias is then expanded and __pgetc() is called to fetch the next character. Since there are none left in the alias string __pgetc() calls preadbuffer() which pops the string, reverts to the previous input and recursively calls __pgetc(). This request is satisified from the pungetc buffer. But the first __pgetc() doesn't know this: it sees the character has come from preadbuffer() so it (incorrectly) updates the pungetc buffer. Resolve the issue by moving the code to pop the string and fetch the next character up from preadbuffer() into __pgetc(). Saves 32-48 bytes. (GitHub issue #413) --- shell/ash.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/shell/ash.c b/shell/ash.c index da139f89b..3435c5f76 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -12155,10 +12155,12 @@ preadbuffer(void) char *q; int more; +#if !ENABLE_PLATFORM_MINGW32 if (unlikely(g_parsefile->strpush)) { popstring(); return __pgetc(); } +#endif if (g_parsefile->buf == NULL) { pgetc_debug("preadbuffer PEOF1"); @@ -12274,8 +12276,15 @@ static int __pgetc(void) if (--g_parsefile->left_in_line >= 0) c = (unsigned char)*g_parsefile->next_to_pgetc++; - else + else { +#if ENABLE_PLATFORM_MINGW32 + if (unlikely(g_parsefile->strpush)) { + popstring(); + return __pgetc(); + } +#endif c = preadbuffer(); + } g_parsefile->lastc[1] = g_parsefile->lastc[0]; g_parsefile->lastc[0] = c; -- cgit v1.2.3-55-g6feb