From 4fb53fb08ce3da8eac13438ce613df20e523c75d Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 1 Aug 2011 14:06:20 +0200 Subject: [PATCH] hush: partially fix wrong expansion on $IFS (bug 4027). In the added testcase, before patch we failed 8 out of 9 tests, now we fail only 2 (4th and 5th). function old new delta expand_on_ifs 225 258 +33 expand_vars_to_list 1038 1054 +16 o_save_ptr_helper 115 119 +4 builtin_umask 132 133 +1 o_addQstr 165 161 -4 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 4/1 up/down: 54/-4) Total: 50 bytes Signed-off-by: Denys Vlasenko --- shell/hush.c | 39 ++++++++++++++----- .../hush-vars/var_expand_on_ifs.right | 9 +++++ .../hush-vars/var_expand_on_ifs.tests | 11 ++++++ 3 files changed, 50 insertions(+), 9 deletions(-) create mode 100644 shell/hush_test/hush-vars/var_expand_on_ifs.right create mode 100755 shell/hush_test/hush-vars/var_expand_on_ifs.tests diff --git a/shell/hush.c b/shell/hush.c index 1082738a2..503cb770b 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -2281,7 +2281,7 @@ static void o_addqblock(o_string *o, const char *str, int len) ordinary_cnt = len; o_addblock(o, str, ordinary_cnt); if (ordinary_cnt == len) - return; + return; /* NUL is already added by o_addblock */ str += ordinary_cnt; len -= ordinary_cnt + 1; /* we are processing + 1 char below */ @@ -2295,8 +2295,8 @@ static void o_addqblock(o_string *o, const char *str, int len) o_grow_by(o, sz); o->data[o->length] = ch; o->length++; - o->data[o->length] = '\0'; } + o->data[o->length] = '\0'; } static void o_addQblock(o_string *o, const char *str, int len) @@ -2385,6 +2385,7 @@ static int o_save_ptr_helper(o_string *o, int n) n, string_len, string_start); o->has_empty_slot = 0; } + o->has_quoted_part = 0; list[n] = (char*)(uintptr_t)string_len; return n + 1; } @@ -4754,8 +4755,13 @@ static void o_addblock_duplicate_backslash(o_string *o, const char *str, int len static int expand_on_ifs(o_string *output, int n, const char *str) { while (1) { - int word_len = strcspn(str, G.ifs); + int word_len; + + if (!*str) /* EOL - do not finalize word */ + break; + word_len = strcspn(str, G.ifs); if (word_len) { + /* We have WORD_LEN leading non-IFS chars */ if (!(output->o_expflags & EXP_FLAG_GLOB)) { o_addblock(output, str, word_len); } else { @@ -4769,13 +4775,25 @@ static int expand_on_ifs(o_string *output, int n, const char *str) /*o_addqblock(output, str, word_len); - WRONG: "v='*'; echo Z$v" prints "Z*" instead of Z* files */ } str += word_len; + if (!*str) /* EOL - do not finalize word */ + break; + goto finalize; /* optimization (can just fall thru) */ + } + /* Case "v=' a'; echo ''$v": we do need to finalize empty word */ + if (output->has_quoted_part + /* Case "v=' a'; echo $v": + * here nothing precedes the space in $v expansion, + * therefore we should not finish the word + * (IOW: if there *is* word to finalize, only then do it) + */ + || (output->length && output->data[output->length - 1]) + ) { + finalize: + o_addchr(output, '\0'); + debug_print_list("expand_on_ifs", output, n); + n = o_save_ptr(output, n); } - if (!*str) /* EOL - do not finalize word */ - break; - o_addchr(output, '\0'); - debug_print_list("expand_on_ifs", output, n); - n = o_save_ptr(output, n); - str += strspn(str, G.ifs); /* skip ifs chars */ + str += strspn(str, G.ifs); /* skip IFS chars */ } debug_print_list("expand_on_ifs[1]", output, n); return n; @@ -5270,11 +5288,13 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg) if (G.ifs[0]) o_addchr(output, G.ifs[0]); } + output->has_quoted_part = 1; } break; } case SPECIAL_VAR_SYMBOL: /* */ /* "Empty variable", used to make "" etc to not disappear */ + output->has_quoted_part = 1; arg++; cant_be_null = 0x80; break; @@ -5316,6 +5336,7 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg) val = NULL; } } else { /* quoted $VAR, val will be appended below */ + output->has_quoted_part = 1; debug_printf_expand("quoted '%s', output->o_escape:%d\n", val, !!(output->o_expflags & EXP_FLAG_ESC_GLOB_CHARS)); } diff --git a/shell/hush_test/hush-vars/var_expand_on_ifs.right b/shell/hush_test/hush-vars/var_expand_on_ifs.right new file mode 100644 index 000000000..2ed2069f7 --- /dev/null +++ b/shell/hush_test/hush-vars/var_expand_on_ifs.right @@ -0,0 +1,9 @@ +1 a b c +2 a + b c +3 a b c +4 a b c +5 a b c +6 a b + c +7 a b c +8 a b c +9 a b c diff --git a/shell/hush_test/hush-vars/var_expand_on_ifs.tests b/shell/hush_test/hush-vars/var_expand_on_ifs.tests new file mode 100755 index 000000000..a12ff8ec8 --- /dev/null +++ b/shell/hush_test/hush-vars/var_expand_on_ifs.tests @@ -0,0 +1,11 @@ +b=' b ' +e='' +echo 1 a $b c +echo 2 a +$b c +echo 3 a $e$b c +echo 4 a "$e"$b c +echo 5 a ""$b c +echo 6 a $b+ c +echo 7 a $b$e c +echo 8 a $b"$e" c +echo 9 a $b"" c -- 2.25.1