[PATCH] input: Fix overeager NUL deletion in SMALL mode
Herbert Xu <[email protected]> Sat, 20 Jun 2026 17:23:30 +0800
| Newsgroups | org.kernel.vger.dash |
|---|---|
| Message-ID | <[email protected]> |
On Sat, Jun 20, 2026 at 06:50:20AM +0100, Kerin Millar wrote: > > Aye, that it be and no mistake. > > https://git.kernel.org/pub/scm/utils/dash/dash.git/commit/?id=44b15ea09a9ee5872cf477e4ffc6b42ef37d1e46 OK this patch should fix the problem: ---8<--- NUL characters should not be removed from input lines that are yet to be processed because they could become the input to the next executed utility. Fix this by moving the NUL deletion into pgetc when history support is off (IS_DEFINED_SMALL). Also fold __pgetc into pgetc since the only other caller of it is preadbuffer and that logic can also be moved up. Finally add a missing signed char cast for the unget characters. Reported-by: Kerin Millar <[email protected]> Fixes: 44ae22beedf8 ("input: Disable lleft in SMALL mode") Fixes: 2c92409145d0 ("input: Allow MB_LEN_MAX calls to pungetc") Signed-off-by: Herbert Xu <[email protected]> diff --git a/src/input.c b/src/input.c index 0fb2f18..e9b9d33 100644 --- a/src/input.c +++ b/src/input.c @@ -217,26 +217,6 @@ static void freestrings(struct strpush *sp) } -static int __pgetc(void) -{ - int c; - - if (parsefile->unget) { - long unget = -(long)(unsigned)parsefile->unget--; - - return parsefile->nextc[unget]; - } - - if (parsefile->nleft > 0) { - parsefile->nleft--; - c = (signed char)*parsefile->nextc++; - } else - c = preadbuffer(); - - return c; -} - - /* * Read a character from the script, returning PEOF on end of file. * Nul characters in the input are silently discarded. @@ -245,11 +225,39 @@ static int __pgetc(void) int __attribute__((noinline)) pgetc(void) { struct strpush *sp = parsefile->spfree; + int c; if (unlikely(sp)) freestrings(sp); - return __pgetc(); +again: + if (parsefile->unget) { + long unget = -(long)(unsigned)parsefile->unget--; + + return (signed char)parsefile->nextc[unget]; + } + +nextc: + if (likely(parsefile->nleft > 0)) { + parsefile->nleft--; + c = (signed char)*parsefile->nextc++; + } else if (unlikely(parsefile->strpush)) { + popstring(); + /* The freestrings call must be delayed til the next + * pgetc call for PEOA to work properly. + */ + goto again; + } else + c = preadbuffer(); + + /* delete nul characters */ + if (IS_DEFINED_SMALL && unlikely(!c)) { + parsefile->nextc = memmove(parsefile->nextc - 1, + parsefile->nextc, parsefile->nleft); + goto nextc; + } + + return c; } int pgetc_eoa(void) @@ -374,10 +382,6 @@ static int preadbuffer(void) int more; char *q; - if (unlikely(parsefile->strpush)) { - popstring(); - return __pgetc(); - } if (parsefile->eof & 2) { eof: parsefile->eof = 3; @@ -408,6 +412,12 @@ again: } } + if (IS_DEFINED_SMALL) { + q += more; + more = 0; + goto done; + } + /* delete nul characters */ for (;;) { int c; @@ -422,9 +432,6 @@ again: q++; - if (IS_DEFINED_SMALL) - goto check; - switch (c) { case '\n': goto done; @@ -439,11 +446,8 @@ again: } check: - if (more <= 0) { - if (!IS_DEFINED_SMALL) - goto again; - break; - } + if (more <= 0) + goto again; } done: input_set_lleft(parsefile, more); -- Email: Herbert Xu <[email protected]> Home Page: http://gondor.apana.org.au/~herbert/ PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt