139 lines
4.2 KiB
Diff
139 lines
4.2 KiB
Diff
From: Martijn Dekker <martijn@inlv.org>
|
|
Date: Thu, 29 May 2025 00:56:48 +0100
|
|
Subject: Fix corruption in varname length calculation (re: c3651897)
|
|
|
|
# Backport: regenerated for downstream ksh 1.0.10 (c10s)
|
|
# Upstream-commit: e19960076327debb272f11041b26e7c2925d8a0a
|
|
# Also-includes: b6cd1082 (regression test)
|
|
# Also-includes: ac343fd7 + f99fbafa (line continuation fix)
|
|
diff --git a/src/cmd/ksh93/sh/lex.c b/src/cmd/ksh93/sh/lex.c
|
|
index 354bc20..d86f6ff 100644
|
|
--- a/src/cmd/ksh93/sh/lex.c
|
|
+++ b/src/cmd/ksh93/sh/lex.c
|
|
@@ -249,8 +249,7 @@ int sh_lex(Lex_t* lp)
|
|
int n, c, mode=ST_BEGIN, wordflags=0;
|
|
int inlevel=lp->lexd.level, assignment=0, ingrave=0;
|
|
int epatchar=0;
|
|
- char *varnamefirst = NULL;
|
|
- int varnamelength = 0;
|
|
+ int varnametry = 0, varnamecount = 0, varnamelength = 0;
|
|
SETLEN(1);
|
|
if(lp->lexd.paren)
|
|
{
|
|
@@ -308,7 +307,11 @@ int sh_lex(Lex_t* lp)
|
|
{
|
|
/* skip over characters in the current state */
|
|
state = sh_lexstates[mode];
|
|
- while((n=STATE(state,c))==0);
|
|
+ do {
|
|
+ n = STATE(state,c);
|
|
+ if (varnametry)
|
|
+ varnamecount += LEN;
|
|
+ } while (n == 0);
|
|
switch(n)
|
|
{
|
|
case S_BREAK:
|
|
@@ -583,6 +586,8 @@ int sh_lex(Lex_t* lp)
|
|
lp->comp_assign = 0;
|
|
return lp->token=c;
|
|
case S_ESC:
|
|
+ if(varnametry)
|
|
+ varnamecount--;
|
|
/* check for \<new-line> */
|
|
fcgetc(n);
|
|
c=2;
|
|
@@ -650,14 +655,18 @@ int sh_lex(Lex_t* lp)
|
|
}
|
|
/* FALLTHROUGH */
|
|
case S_RES:
|
|
- varnamefirst = fcseek(0) - LEN;
|
|
+ varnametry = 1;
|
|
+ varnamecount = LEN;
|
|
if(!lp->lexd.dolparen)
|
|
lp->lexd.first = fcseek(0)-LEN;
|
|
else if(lp->lexd.docword)
|
|
lp->lexd.docend = fcseek(0)-LEN;
|
|
mode = ST_NAME;
|
|
if(c=='.')
|
|
+ {
|
|
fcseek(-LEN);
|
|
+ varnamecount -= LEN;
|
|
+ }
|
|
if(n!=S_TILDE)
|
|
continue;
|
|
tilde:
|
|
@@ -1116,12 +1125,13 @@ int sh_lex(Lex_t* lp)
|
|
goto epat;
|
|
continue;
|
|
case S_EQ:
|
|
- if(varnamefirst && !varnamelength)
|
|
+ if(varnametry && !varnamelength)
|
|
{
|
|
- varnamelength = fcseek(0) - LEN - varnamefirst;
|
|
+ varnamelength = varnamecount - LEN;
|
|
if(varnamelength > 0 && fcpeek(-LEN - 1) == '+')
|
|
varnamelength--; /* += */
|
|
}
|
|
+ varnametry = 0;
|
|
assignment = lp->assignok;
|
|
/* FALLTHROUGH */
|
|
case S_COLON:
|
|
@@ -1136,8 +1146,8 @@ int sh_lex(Lex_t* lp)
|
|
}
|
|
break;
|
|
case S_BRACT:
|
|
- if(varnamefirst && !varnamelength && fcpeek(-LEN - 1)!='.')
|
|
- varnamelength = fcseek(0) - LEN - varnamefirst;
|
|
+ if(varnametry && !varnamelength && fcpeek(-LEN - 1)!='.')
|
|
+ varnamelength = varnamecount - LEN;
|
|
/* check for possible subscript */
|
|
if((n=endchar(lp))==RBRACT || n==RPAREN ||
|
|
(mode==ST_BRACE) ||
|
|
diff --git a/src/cmd/ksh93/tests/locale.sh b/src/cmd/ksh93/tests/locale.sh
|
|
index 9fae8b1..c677836 100755
|
|
--- a/src/cmd/ksh93/tests/locale.sh
|
|
+++ b/src/cmd/ksh93/tests/locale.sh
|
|
@@ -468,5 +468,16 @@ then unset s "${!LC_@}"
|
|
"(expected $(printf %q "$exp"); got $(printf %q "$got"))"
|
|
fi
|
|
|
|
+# ======
|
|
+# https://github.com/ksh93/ksh/issues/861#issuecomment-2917738184
|
|
+if ((SHOPT_MULTIBYTE))
|
|
+then export LANG=C.UTF-8
|
|
+ got=$(set +x; redirect 2>&1; readonly コーンシェル=OK; echo "$コーンシェル")
|
|
+ exp=OK
|
|
+ [[ $got == "$exp" ]] || err_exit 'declaration command assignment with multibyte variable name' \
|
|
+ "(expected $(printf %q "$exp"); got $(printf %q "$got"))"
|
|
+ unset LANG
|
|
+fi
|
|
+
|
|
# ======
|
|
exit $((Errors<125?Errors:125))
|
|
diff --git a/src/cmd/ksh93/tests/variables.sh b/src/cmd/ksh93/tests/variables.sh
|
|
index 5754085..91c3a37 100755
|
|
--- a/src/cmd/ksh93/tests/variables.sh
|
|
+++ b/src/cmd/ksh93/tests/variables.sh
|
|
@@ -1626,5 +1626,18 @@ got=$(set +x; { "$SHELL" -c '
|
|
(((e=$?)==0)) || err_exit "crash after unsetting SHLVL" \
|
|
"(expected status 0, got status $e$( ((e>128)) && print -n /SIG && kill -l "$e"))"
|
|
|
|
+# ======
|
|
+# https://github.com/ksh93/ksh/issues/861
|
|
+unset i
|
|
+typeset -i i
|
|
+for ((i=0; i<10000; i++))
|
|
+do echo "readonly this_is_very_long_variable_name_number_$i=1"
|
|
+done >issue861.sh
|
|
+chmod +x issue861.sh
|
|
+got=$(./issue861.sh 2>&1)
|
|
+[[ e=$? -eq 0 && -z $got ]] || err_exit "variable name length corrupted when reading across buffer boundary" \
|
|
+ "(got status $e, $(printf %q "$got"))"
|
|
+unset i
|
|
+
|
|
# ======
|
|
exit $((Errors<125?Errors:125))
|
|
--
|
|
2.53.0
|
|
|