busybox: 1.13.3 hush fix
authorPeter Korsgaard <jacmet@sunsite.dk>
Tue, 24 Mar 2009 08:51:57 +0000 (08:51 -0000)
committerPeter Korsgaard <jacmet@sunsite.dk>
Tue, 24 Mar 2009 08:51:57 +0000 (08:51 -0000)
package/busybox/busybox-1.13.3-hush.patch [new file with mode: 0644]

diff --git a/package/busybox/busybox-1.13.3-hush.patch b/package/busybox/busybox-1.13.3-hush.patch
new file mode 100644 (file)
index 0000000..742f912
--- /dev/null
@@ -0,0 +1,179 @@
+diff -urpN busybox-1.13.3/shell/hush.c busybox-1.13.3-hush/shell/hush.c
+--- busybox-1.13.3/shell/hush.c        2009-02-26 12:46:55.000000000 +0100
++++ busybox-1.13.3-hush/shell/hush.c   2009-03-22 12:46:42.000000000 +0100
+@@ -458,8 +458,11 @@ struct globals {
+       smallint fake_mode;
+       /* these three support $?, $#, and $1 */
+       smalluint last_return_code;
+-      char **global_argv;
++      /* is global_argv and global_argv[1..n] malloced? (note: not [0]) */
++      smalluint global_args_malloced;
++      /* how many non-NULL argv's we have. NB: $# + 1 */
+       int global_argc;
++      char **global_argv;
+ #if ENABLE_HUSH_LOOPS
+       unsigned depth_break_continue;
+       unsigned depth_of_loop;
+@@ -633,7 +636,7 @@ static char *unbackslash(char *src)
+       return dst;
+ }
+-static char **add_strings_to_strings(char **strings, char **add)
++static char **add_strings_to_strings(char **strings, char **add, int need_to_dup)
+ {
+       int i;
+       unsigned count1;
+@@ -658,7 +661,7 @@ static char **add_strings_to_strings(cha
+       v[count1 + count2] = NULL;
+       i = count2;
+       while (--i >= 0)
+-              v[count1 + i] = add[i];
++              v[count1 + i] = (need_to_dup ? xstrdup(add[i]) : add[i]);
+       return v;
+ }
+@@ -667,7 +670,7 @@ static char **add_string_to_strings(char
+       char *v[2];
+       v[0] = add;
+       v[1] = NULL;
+-      return add_strings_to_strings(strings, v);
++      return add_strings_to_strings(strings, v, /*dup:*/ 0);
+ }
+ static void putenv_all(char **strings)
+@@ -1213,8 +1216,13 @@ static int o_glob(o_string *o, int n)
+  * Otherwise, just finish current list[] and start new */
+ static int o_save_ptr(o_string *o, int n)
+ {
+-      if (o->o_glob)
+-              return o_glob(o, n); /* o_save_ptr_helper is inside */
++      if (o->o_glob) { /* if globbing is requested */
++              /* If o->has_empty_slot, list[n] was already globbed
++               * (if it was requested back then when it was filled)
++               * so don't do that again! */
++              if (!o->has_empty_slot)
++                      return o_glob(o, n); /* o_save_ptr_helper is inside */
++      }
+       return o_save_ptr_helper(o, n);
+ }
+@@ -4279,6 +4287,11 @@ int hush_main(int argc, char **argv)
+               switch (opt) {
+               case 'c':
+                       G.global_argv = argv + optind;
++                      if (!argv[optind]) {
++                              /* -c 'script' (no params): prevent empty $0 */
++                              *--G.global_argv = argv[0];
++                              optind--;
++                      } /* else -c 'script' PAR0 PAR1: $0 is PAR0 */
+                       G.global_argc = argc - optind;
+                       opt = parse_and_run_string(optarg, 0 /* parse_flag */);
+                       goto final_return;
+@@ -4639,17 +4652,68 @@ static int builtin_read(char **argv)
+       return set_local_var(string, 0);
+ }
+-/* built-in 'set [VAR=value]' handler */
++/* built-in 'set' handler
++ * SUSv3 says:
++ * set [-abCefmnuvx] [-h] [-o option] [argument...]
++ * set [+abCefmnuvx] [+h] [+o option] [argument...]
++ * set -- [argument...]
++ * set -o
++ * set +o
++ * Implementations shall support the options in both their hyphen and
++ * plus-sign forms. These options can also be specified as options to sh.
++ * Examples:
++ * Write out all variables and their values: set
++ * Set $1, $2, and $3 and set "$#" to 3: set c a b
++ * Turn on the -x and -v options: set -xv
++ * Unset all positional parameters: set --
++ * Set $1 to the value of x, even if it begins with '-' or '+': set -- "$x"
++ * Set the positional parameters to the expansion of x, even if x expands
++ * with a leading '-' or '+': set -- $x
++ *
++ * So far, we only support "set -- [argument...]" by ignoring all options
++ * (also, "-o option" will be mishandled by taking "option" as parameter #1).
++ */
+ static int builtin_set(char **argv)
+ {
+-      char *temp = argv[1];
+       struct variable *e;
++      char **pp;
++      char *arg = *++argv;
+-      if (temp == NULL)
++      if (arg == NULL) {
+               for (e = G.top_var; e; e = e->next)
+                       puts(e->varstr);
+-      else
+-              set_local_var(xstrdup(temp), 0);
++      } else {
++              /* NB: G.global_argv[0] ($0) is never freed/changed */
++
++              if (G.global_args_malloced) {
++                      pp = G.global_argv;
++                      while (*++pp)
++                              free(*pp);
++                      G.global_argv[1] = NULL;
++              } else {
++                      G.global_args_malloced = 1;
++                      pp = xzalloc(sizeof(pp[0]) * 2);
++                      pp[0] = G.global_argv[0]; /* retain $0 */
++                      G.global_argv = pp;
++              }
++              do  {
++                      if (arg[0] == '+')
++                              continue;
++                      if (arg[0] != '-')
++                              break;
++                      if (arg[1] == '-' && arg[2] == '\0') {
++                              argv++;
++                              break;
++                      }
++              } while ((arg = *++argv) != NULL);
++              /* Now argv[0] is 1st argument */
++
++              /* This realloc's G.global_argv */
++              G.global_argv = pp = add_strings_to_strings(G.global_argv, argv, /*dup:*/ 1);
++              G.global_argc = 1;
++              while (*++pp)
++                      G.global_argc++;
++      }
+       return EXIT_SUCCESS;
+ }
+@@ -4661,9 +4725,14 @@ static int builtin_shift(char **argv)
+               n = atoi(argv[1]);
+       }
+       if (n >= 0 && n < G.global_argc) {
+-              G.global_argv[n] = G.global_argv[0];
++              if (G.global_args_malloced) {
++                      int m = 1;
++                      while (m <= n)
++                              free(G.global_argv[m++]);
++              }
+               G.global_argc -= n;
+-              G.global_argv += n;
++              memmove(&G.global_argv[1], &G.global_argv[n+1],
++                              G.global_argc * sizeof(G.global_argv[0]));
+               return EXIT_SUCCESS;
+       }
+       return EXIT_FAILURE;
+diff -urpN busybox-1.13.3/shell/hush_test/hush-parsing/starquoted2.right busybox-1.13.3-hush/shell/hush_test/hush-parsing/starquoted2.right
+--- busybox-1.13.3/shell/hush_test/hush-parsing/starquoted2.right      2009-02-26 12:46:52.000000000 +0100
++++ busybox-1.13.3-hush/shell/hush_test/hush-parsing/starquoted2.right 2009-03-22 12:46:20.000000000 +0100
+@@ -1,2 +1,3 @@
+ Should be printed
+ Should be printed
++Empty:
+diff -urpN busybox-1.13.3/shell/hush_test/hush-parsing/starquoted2.tests busybox-1.13.3-hush/shell/hush_test/hush-parsing/starquoted2.tests
+--- busybox-1.13.3/shell/hush_test/hush-parsing/starquoted2.tests      2009-02-26 12:46:52.000000000 +0100
++++ busybox-1.13.3-hush/shell/hush_test/hush-parsing/starquoted2.tests 2009-03-22 12:46:20.000000000 +0100
+@@ -12,3 +12,6 @@ for a in "$@"""; do echo Should not be p
+ for a in """$@"; do echo Should not be printed; done
+ for a in """$@"''"$@"''; do echo Should not be printed; done
+ for a in ""; do echo Should be printed; done
++
++# Bug 207: "$@" expands to nothing, and we erroneously glob "%s\\n" twice:
++printf "Empty:%s\\n" "$@"