From 97c3b5e3ff252b3399d10835d5c906886a7499f4 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 19 Jun 2021 15:28:10 +0200 Subject: [PATCH] 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 --- .../ash-parsing/bkslash_newline4.right | 4 +++ .../ash-parsing/bkslash_newline4.tests | 14 ++++++++++ shell/hush.c | 28 ++++++++++++++++++- .../hush-parsing/bkslash_newline4.right | 4 +++ .../hush-parsing/bkslash_newline4.tests | 14 ++++++++++ shell/hush_test/hush-vars/var6.right | 2 +- 6 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 shell/ash_test/ash-parsing/bkslash_newline4.right create mode 100755 shell/ash_test/ash-parsing/bkslash_newline4.tests create mode 100644 shell/hush_test/hush-parsing/bkslash_newline4.right create mode 100755 shell/hush_test/hush-parsing/bkslash_newline4.tests diff --git a/shell/ash_test/ash-parsing/bkslash_newline4.right b/shell/ash_test/ash-parsing/bkslash_newline4.right new file mode 100644 index 000000000..2110716d1 --- /dev/null +++ b/shell/ash_test/ash-parsing/bkslash_newline4.right @@ -0,0 +1,4 @@ +1:1 +22:22 +3:3 +Ok:0 diff --git a/shell/ash_test/ash-parsing/bkslash_newline4.tests b/shell/ash_test/ash-parsing/bkslash_newline4.tests new file mode 100755 index 000000000..c8f5037c4 --- /dev/null +++ b/shell/ash_test/ash-parsing/bkslash_newline4.tests @@ -0,0 +1,14 @@ +set -- 1 22 333 +echo 1:$\ +1 +echo 22:$\ +{\ +2\ +} +echo 3:$\ +{\ +#\ +3\ +} +echo Ok:$\ +? diff --git a/shell/hush.c b/shell/hush.c index e8d24d40b..1aa0a400d 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -4998,6 +4998,32 @@ static int parse_dollar(o_string *as_string, * which check invalid constructs like ${%}. * 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...} is valid */ + goto eat_until_closing; + if (!isdigit(ch)) + goto bad_dollar_syntax; + } + } else while (1) { unsigned pos; @@ -5008,7 +5034,6 @@ static int parse_dollar(o_string *as_string, nommu_addchr(as_string, ch); if (ch == '}') break; - if (!isalnum(ch) && ch != '_') { unsigned end_ch; unsigned char last_ch; @@ -5027,6 +5052,7 @@ static int parse_dollar(o_string *as_string, * special var name, e.g. ${#!}. */ } + eat_until_closing: /* Eat everything until closing '}' (or ':') */ end_ch = '}'; if (BASH_SUBSTR diff --git a/shell/hush_test/hush-parsing/bkslash_newline4.right b/shell/hush_test/hush-parsing/bkslash_newline4.right new file mode 100644 index 000000000..2110716d1 --- /dev/null +++ b/shell/hush_test/hush-parsing/bkslash_newline4.right @@ -0,0 +1,4 @@ +1:1 +22:22 +3:3 +Ok:0 diff --git a/shell/hush_test/hush-parsing/bkslash_newline4.tests b/shell/hush_test/hush-parsing/bkslash_newline4.tests new file mode 100755 index 000000000..c8f5037c4 --- /dev/null +++ b/shell/hush_test/hush-parsing/bkslash_newline4.tests @@ -0,0 +1,14 @@ +set -- 1 22 333 +echo 1:$\ +1 +echo 22:$\ +{\ +2\ +} +echo 3:$\ +{\ +#\ +3\ +} +echo Ok:$\ +? diff --git a/shell/hush_test/hush-vars/var6.right b/shell/hush_test/hush-vars/var6.right index 40e67fdf5..5e28d2fab 100644 --- a/shell/hush_test/hush-vars/var6.right +++ b/shell/hush_test/hush-vars/var6.right @@ -1,2 +1,2 @@ -hush: invalid number '1q' +hush: syntax error: unterminated ${name} hush: syntax error: unterminated ${name}