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" "$@"