aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--shell/hush.c26
-rw-r--r--shell/hush_test/hush-parsing/starquoted2.right2
-rwxr-xr-xshell/hush_test/hush-parsing/starquoted2.tests14
3 files changed, 36 insertions, 6 deletions
diff --git a/shell/hush.c b/shell/hush.c
index 5b5a54241..2c1d31c6d 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -2380,7 +2380,10 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask)
2380 p = strchr(p, SPECIAL_VAR_SYMBOL); 2380 p = strchr(p, SPECIAL_VAR_SYMBOL);
2381 2381
2382 first_ch = arg[0] | or_mask; /* forced to "quoted" if or_mask = 0x80 */ 2382 first_ch = arg[0] | or_mask; /* forced to "quoted" if or_mask = 0x80 */
2383 ored_ch |= first_ch; 2383 /* "$@" is special. Even if quoted, it can still
2384 * expand to nothing (not even an empty string) */
2385 if ((first_ch & 0x7f) != '@')
2386 ored_ch |= first_ch;
2384 val = NULL; 2387 val = NULL;
2385 switch (first_ch & 0x7f) { 2388 switch (first_ch & 0x7f) {
2386 /* Highest bit in first_ch indicates that var is double-quoted */ 2389 /* Highest bit in first_ch indicates that var is double-quoted */
@@ -2401,6 +2404,7 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask)
2401 i = 1; 2404 i = 1;
2402 if (!global_argv[i]) 2405 if (!global_argv[i])
2403 break; 2406 break;
2407 ored_ch |= first_ch; /* do it for "$@" _now_, when we know it's not empty */
2404 if (!(first_ch & 0x80)) { /* unquoted $* or $@ */ 2408 if (!(first_ch & 0x80)) { /* unquoted $* or $@ */
2405 smallint sv = output->o_quote; 2409 smallint sv = output->o_quote;
2406 /* unquoted var's contents should be globbed, so don't quote */ 2410 /* unquoted var's contents should be globbed, so don't quote */
@@ -2932,15 +2936,25 @@ static int done_word(o_string *word, struct p_context *ctx)
2932 } 2936 }
2933 } 2937 }
2934#endif 2938#endif
2935 if (word->nonnull /* we saw "xx" or 'xx' */ 2939 if (word->nonnull /* word had "xx" or 'xx' at least as part of it */
2936 /* optimization: and if it's ("" or '') or ($v... or `cmd`...): */ 2940 /* optimization: and if it's ("" or '') or ($v... or `cmd`...): */
2937 && (word->data[0] == '\0' || word->data[0] == SPECIAL_VAR_SYMBOL) 2941 && (word->data[0] == '\0' || word->data[0] == SPECIAL_VAR_SYMBOL)
2938 /* (otherwise it's "abc".... and is already safe) */ 2942 /* (otherwise it's "abc".... and is already safe) */
2939 ) { 2943 ) {
2940 /* Insert "empty variable" reference, this makes 2944 /* but exclude "$@"! it expands to no word despite "" */
2941 * e.g. "", $empty"" etc to not disappear */ 2945 char *p = word->data;
2942 o_addchr(word, SPECIAL_VAR_SYMBOL); 2946 while (p[0] == SPECIAL_VAR_SYMBOL
2943 o_addchr(word, SPECIAL_VAR_SYMBOL); 2947 && (p[1] & 0x7f) == '@'
2948 && p[2] == SPECIAL_VAR_SYMBOL
2949 ) {
2950 p += 3;
2951 }
2952 if (p == word->data || p[0] != '\0') {
2953 /* Insert "empty variable" reference, this makes
2954 * e.g. "", $empty"" etc to not disappear */
2955 o_addchr(word, SPECIAL_VAR_SYMBOL);
2956 o_addchr(word, SPECIAL_VAR_SYMBOL);
2957 }
2944 } 2958 }
2945 child->argv = add_malloced_string_to_strings(child->argv, xstrdup(word->data)); 2959 child->argv = add_malloced_string_to_strings(child->argv, xstrdup(word->data));
2946 debug_print_strings("word appended to argv", child->argv); 2960 debug_print_strings("word appended to argv", child->argv);
diff --git a/shell/hush_test/hush-parsing/starquoted2.right b/shell/hush_test/hush-parsing/starquoted2.right
new file mode 100644
index 000000000..46f24369e
--- /dev/null
+++ b/shell/hush_test/hush-parsing/starquoted2.right
@@ -0,0 +1,2 @@
1Should be printed
2Should be printed
diff --git a/shell/hush_test/hush-parsing/starquoted2.tests b/shell/hush_test/hush-parsing/starquoted2.tests
new file mode 100755
index 000000000..782d71b88
--- /dev/null
+++ b/shell/hush_test/hush-parsing/starquoted2.tests
@@ -0,0 +1,14 @@
1if test $# != 0; then
2 exec "$THIS_SH" "$0"
3fi
4
5# No params!
6for a in "$*"; do echo Should be printed; done
7for a in "$@"; do echo Should not be printed; done
8# Yes, believe it or not, bash is mesmerized by "$@" and stops
9# treating "" as "this word cannot be expanded to nothing,
10# but must be at least null string". Now it can be expanded to nothing.
11for a in "$@"""; do echo Should not be printed; done
12for a in """$@"; do echo Should not be printed; done
13for a in """$@"''"$@"''; do echo Should not be printed; done
14for a in ""; do echo Should be printed; done