From 5ed9ffd6c49bbc7114b5762d7cb228f3e43dc8ab Mon Sep 17 00:00:00 2001 From: Martijn Dekker Date: Sat, 5 Sep 2020 16:20:22 +0200 Subject: [PATCH] This fixes erroneous syntax errors in parameter expansions such as ${var:-wor)d} or ${var+w(ord}. The parentheses now correctly lose their normal grammatical meaning within the braces. Fix by Eric Scrivner (@etscrivner) from July 2018 backported from ksh2020. This fix complies with POSIX: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_02 src/cmd/ksh93/sh/lex.c: sh_lex(): - Set the ST_QUOTE state when analysing a modifier with parameter expansions using operators ':', '-', '+', '='. This state causes subsequent characters (including parentheses) to be considered quoted, suppressing their normal grammatical meaning. src/cmd/ksh93/sh/macro.c: varsub(): - Same for skipping the expansion. Fixes: https://github.com/ksh93/ksh/issues/126 Prior discussion: https://github.com/att/ast/issues/475 --- NEWS | 6 ++++++ src/cmd/ksh93/include/version.h | 2 +- src/cmd/ksh93/sh/lex.c | 5 +++++ src/cmd/ksh93/sh/macro.c | 3 ++- src/cmd/ksh93/tests/variables.sh | 34 ++++++++++++++++++++++++++++++++ 5 files changed, 48 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 18134d46e..51dd10539 100644 --- a/NEWS +++ b/NEWS @@ -3,6 +3,12 @@ For full details, see the git log at: https://github.com/ksh93/ksh Any uppercase BUG_* names are modernish shell bug IDs. +2020-09-05: + +- Fixed erroneous syntax errors in parameter expansions such as ${var:-wor)d} + or ${var+w(ord}. The parentheses now correctly lose their normal grammatical + meaning within the braces. Fix by Eric Scrivner backported from ksh2020. + 2020-09-04: - Fixed a bug that caused a syntax error to be thrown if the special parameter diff --git a/src/cmd/ksh93/include/version.h b/src/cmd/ksh93/include/version.h index 1f72bd3c0..e06fe1525 100644 --- a/src/cmd/ksh93/include/version.h +++ b/src/cmd/ksh93/include/version.h @@ -17,4 +17,4 @@ * David Korn * * * ***********************************************************************/ -#define SH_RELEASE "93u+m 2020-09-04" +#define SH_RELEASE "93u+m 2020-09-05" diff --git a/src/cmd/ksh93/sh/lex.c b/src/cmd/ksh93/sh/lex.c index 2aa71a776..da21d9d56 100644 --- a/src/cmd/ksh93/sh/lex.c +++ b/src/cmd/ksh93/sh/lex.c @@ -1018,6 +1018,11 @@ int sh_lex(Lex_t* lp) if(lp->kiafile) refvar(lp,1); #endif /* SHOPT_KIA */ + if(c == ':' || c == '-' || c == '+' || c == '=') + { + mode = ST_QUOTE; + continue; + } if(c!=':' && fcgetc(n)>0) { if(n!=c) diff --git a/src/cmd/ksh93/sh/macro.c b/src/cmd/ksh93/sh/macro.c index 36b299988..67c454925 100644 --- a/src/cmd/ksh93/sh/macro.c +++ b/src/cmd/ksh93/sh/macro.c @@ -1628,7 +1628,8 @@ retry1: } else { - sh_lexskip(lp,RBRACE,0,(!newops&&mp->quote)?ST_QUOTE:ST_NESTED); + int state = (!newops && mp->quote || c=='-' || c=='+' || c=='=') ? ST_QUOTE : ST_NESTED; + sh_lexskip(lp, RBRACE, 0, state); stkseek(stkp,offset); } argp=stkptr(stkp,offset); diff --git a/src/cmd/ksh93/tests/variables.sh b/src/cmd/ksh93/tests/variables.sh index 3604c1267..f122ed5d4 100755 --- a/src/cmd/ksh93/tests/variables.sh +++ b/src/cmd/ksh93/tests/variables.sh @@ -1040,5 +1040,39 @@ wait # ${.sh.pid} should be the same as $$ in the parent shell [[ $$ == ${.sh.pid} ]] || err_exit "\${.sh.pid} and \$$ differ in the parent shell (expected $$, got ${.sh.pid})" +# ====== +# Parentheses after the '-', '+', and '=' expansion operators were causing syntax errors. +# Check both the unset variable case and the set variable case for each set of symbols. + +unset -v foo +for op in - :- = := +do for word in '(word)' 'w(or)d' '(wor)d' 'w(ord)' 'w(ord' 'wor)d' + do exp=$(set +x; eval "echo \${foo${op}${word}}" 2>&1) + if [[ $exp != "$word" ]] + then err_exit "\${foo${op}${word}} when foo is not set: expected \"$word\", got \"$exp\"" + fi + done +done + +foo=some_value +for op in - :- = := +do for word in '(word)' 'w(or)d' '(wor)d' 'w(ord)' 'w(ord' 'wor)d' + do exp=$(set +x; eval "echo \${foo${op}${word}}" 2>&1) + if [[ $exp != "$foo" ]] + then err_exit "\${foo${op}${word}} when foo is set: expected \"$foo\", got \"$exp\"" + fi + done +done + +unset -v foo +for op in + :+ +do for word in '(word)' 'w(or)d' '(wor)d' 'w(ord)' 'w(ord' 'wor)d' + do exp=$(set +x; eval "echo \${foo${op}${word}}" 2>&1) + if [[ $exp != "" ]] + then err_exit "\${foo${op}${word}} when foo is not set: expected null, got \"$exp\"" + fi + done +done + # ====== exit $((Errors<125?Errors:125))