app-shells/dash: fix read misbehaviour

Closes: https://bugs.gentoo.org/977650
Thanks-to: Kerin Millar <kfm@plushkava.net>
Signed-off-by: Sam James <sam@gentoo.org>
This commit is contained in:
Sam James
2026-06-21 08:40:46 +01:00
parent be2b3f6ac0
commit 51aa4abfc1
2 changed files with 218 additions and 0 deletions

View File

@@ -0,0 +1,71 @@
# Copyright 1999-2026 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2
EAPI=8
inherit flag-o-matic toolchain-funcs
DESCRIPTION="Debian Almquist Shell"
HOMEPAGE="http://gondor.apana.org.au/~herbert/dash/"
if [[ ${PV} == 9999 ]] ; then
EGIT_REPO_URI="https://git.kernel.org/pub/scm/utils/dash/dash.git"
inherit autotools git-r3
else
SRC_URI="http://gondor.apana.org.au/~herbert/dash/files/${P}.tar.gz"
KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~hppa ~loong ~m68k ~mips ~ppc ~ppc64 ~riscv ~s390 ~sparc ~x86 ~arm64-macos ~x64-macos ~x64-solaris"
fi
LICENSE="BSD"
SLOT="0"
IUSE="libedit static"
BDEPEND="virtual/pkgconfig"
RDEPEND="!static? ( libedit? ( dev-libs/libedit ) )"
DEPEND="
${RDEPEND}
libedit? ( static? ( dev-libs/libedit[static-libs] ) )
"
PATCHES=(
"${FILESDIR}"/0001-builtin-Fix-octal-escapes-in-dollar-single-quotes.patch
"${FILESDIR}"/0002-builtin-Fix-unaligned-access-in-conv_escape.patch
"${FILESDIR}"/0003-input-Fix-overeager-NUL-deletion-in-SMALL-mode.patch
)
src_prepare() {
default
[[ ${PV} == 9999 ]] && eautoreconf
# Use pkg-config for libedit linkage
sed -i \
-e "/LIBS/s:-ledit:\`$(tc-getPKG_CONFIG) --libs libedit $(usex static --static '')\`:" \
configure || die
}
src_configure() {
if [[ ${CHOST} == *-solaris* ]] ; then
# don't redefine stat, open, dirent, etc. on Solaris
export ac_cv_func_stat64=yes
export ac_cv_func_open64=yes
fi
if [[ ${CHOST} == powerpc-*-darwin* ]] ; then
sed -i -e 's/= stpncpy(s, \([^,]\+\), \([0-9]\+\))/+= snprintf(s, \2, "%s", \1)/' \
src/jobs.c || die
fi
use static && append-ldflags -static
append-cppflags -DJOBS=$(usex libedit 1 0)
# Do not pass --enable-glob due to #443552.
local myeconfargs=(
CC_FOR_BUILD="$(tc-getBUILD_CC)"
--bindir="${EPREFIX}"/bin
--enable-fnmatch
$(use_with libedit)
)
econf "${myeconfargs[@]}"
}

View File

@@ -0,0 +1,147 @@
From e170d9a49b3652460d6272bba9cd20afbb8140f2 Mon Sep 17 00:00:00 2001
From: Herbert Xu <herbert@gondor.apana.org.au>
Date: Sat, 20 Jun 2026 17:23:30 +0800
Subject: [PATCH] input: Fix overeager NUL deletion in SMALL mode
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 <kfm@plushkava.net>
Fixes: 44ae22beedf8 ("input: Disable lleft in SMALL mode")
Fixes: 2c92409145d0 ("input: Allow MB_LEN_MAX calls to pungetc")
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
src/input.c | 66 ++++++++++++++++++++++++++++-------------------------
1 file changed, 35 insertions(+), 31 deletions(-)
diff --git a/src/input.c b/src/input.c
index 0fb2f18..e9b9d33 100644
--- a/src/input.c
+++ b/src/input.c
@@ -217,39 +217,47 @@ static void freestrings(struct strpush *sp)
}
-static int __pgetc(void)
+/*
+ * Read a character from the script, returning PEOF on end of file.
+ * Nul characters in the input are silently discarded.
+ */
+
+int __attribute__((noinline)) pgetc(void)
{
+ struct strpush *sp = parsefile->spfree;
int c;
+ if (unlikely(sp))
+ freestrings(sp);
+
+again:
if (parsefile->unget) {
long unget = -(long)(unsigned)parsefile->unget--;
- return parsefile->nextc[unget];
+ return (signed char)parsefile->nextc[unget];
}
- if (parsefile->nleft > 0) {
+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();
- return c;
-}
-
-
-/*
- * Read a character from the script, returning PEOF on end of file.
- * Nul characters in the input are silently discarded.
- */
-
-int __attribute__((noinline)) pgetc(void)
-{
- struct strpush *sp = parsefile->spfree;
-
- if (unlikely(sp))
- freestrings(sp);
+ /* delete nul characters */
+ if (IS_DEFINED_SMALL && unlikely(!c)) {
+ parsefile->nextc = memmove(parsefile->nextc - 1,
+ parsefile->nextc, parsefile->nleft);
+ goto nextc;
+ }
- return __pgetc();
+ 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);
--
2.53.0