hush: fix bkslash+newline handling and number validation in ${NN} and ${#NN}

Entering "${1a}" into interactive shell was making it exit.

function                                             old     new   delta
parse_dollar                                         824     958    +134
i_getch_and_eat_bkslash_nl                             -      44     +44
parse_expr                                           917     938     +21
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 2/0 up/down: 199/0)             Total: 199 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Denys Vlasenko 2021-06-19 15:28:10 +02:00
parent fd217c1cbf
commit 97c3b5e3ff
6 changed files with 64 additions and 2 deletions

View File

@ -0,0 +1,4 @@
1:1
22:22
3:3
Ok:0

View File

@ -0,0 +1,14 @@
set -- 1 22 333
echo 1:$\
1
echo 22:$\
{\
2\
}
echo 3:$\
{\
#\
3\
}
echo Ok:$\
?

View File

@ -4998,6 +4998,32 @@ static int parse_dollar(o_string *as_string,
* which check invalid constructs like ${%}. * which check invalid constructs like ${%}.
* Oh well... let's check that the var name part is fine... */ * Oh well... let's check that the var name part is fine... */
if (isdigit(len_single_ch)
|| (len_single_ch == '#' && isdigit(i_peek_and_eat_bkslash_nl(input)))
) {
/* Execution engine uses plain xatoi_positive()
* to interpret ${NNN} and {#NNN},
* check syntax here in the parser.
* (bash does not support expressions in ${#NN},
* e.g. ${#$var} and {#1:+WORD} are not supported).
*/
unsigned cnt = 9; /* max 9 digits for ${NN} and 8 for {#NN} */
while (1) {
o_addchr(dest, ch);
debug_printf_parse(": '%c'\n", ch);
ch = i_getch_and_eat_bkslash_nl(input);
nommu_addchr(as_string, ch);
if (ch == '}')
break;
if (--cnt == 0)
goto bad_dollar_syntax;
if (len_single_ch != '#' && strchr(VAR_SUBST_OPS, ch))
/* ${NN<op>...} is valid */
goto eat_until_closing;
if (!isdigit(ch))
goto bad_dollar_syntax;
}
} else
while (1) { while (1) {
unsigned pos; unsigned pos;
@ -5008,7 +5034,6 @@ static int parse_dollar(o_string *as_string,
nommu_addchr(as_string, ch); nommu_addchr(as_string, ch);
if (ch == '}') if (ch == '}')
break; break;
if (!isalnum(ch) && ch != '_') { if (!isalnum(ch) && ch != '_') {
unsigned end_ch; unsigned end_ch;
unsigned char last_ch; unsigned char last_ch;
@ -5027,6 +5052,7 @@ static int parse_dollar(o_string *as_string,
* special var name, e.g. ${#!}. * special var name, e.g. ${#!}.
*/ */
} }
eat_until_closing:
/* Eat everything until closing '}' (or ':') */ /* Eat everything until closing '}' (or ':') */
end_ch = '}'; end_ch = '}';
if (BASH_SUBSTR if (BASH_SUBSTR

View File

@ -0,0 +1,4 @@
1:1
22:22
3:3
Ok:0

View File

@ -0,0 +1,14 @@
set -- 1 22 333
echo 1:$\
1
echo 22:$\
{\
2\
}
echo 3:$\
{\
#\
3\
}
echo Ok:$\
?

View File

@ -1,2 +1,2 @@
hush: invalid number '1q' hush: syntax error: unterminated ${name}
hush: syntax error: unterminated ${name} hush: syntax error: unterminated ${name}