[git commit] hush: fix a nommu bug where a part of function body is lost if run in a pipe

Denys Vlasenko vda.linux at googlemail.com
Fri Sep 4 04:22:10 UTC 2015


commit: http://git.busybox.net/busybox/commit/?id=b5be13ccd9ce2120468a381a5475955013c0f049
branch: http://git.busybox.net/busybox/commit/?id=refs/heads/master

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 shell/hush.c                           |   35 ++++++++++++++++++++++---------
 shell/hush_test/hush-misc/nommu3.right |    2 +
 shell/hush_test/hush-misc/nommu3.tests |   15 +++++++++++++
 3 files changed, 42 insertions(+), 10 deletions(-)

diff --git a/shell/hush.c b/shell/hush.c
index 3ca0449..752080a 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -3161,11 +3161,29 @@ static int reserved_word(o_string *word, struct parse_context *ctx)
 		old->command->group = ctx->list_head;
 		old->command->cmd_type = CMD_NORMAL;
 # if !BB_MMU
-		o_addstr(&old->as_string, ctx->as_string.data);
-		o_free_unsafe(&ctx->as_string);
-		old->command->group_as_string = xstrdup(old->as_string.data);
-		debug_printf_parse("pop, remembering as:'%s'\n",
-				old->command->group_as_string);
+		/* At this point, the compound command's string is in
+		 * ctx->as_string... except for the leading keyword!
+		 * Consider this example: "echo a | if true; then echo a; fi"
+		 * ctx->as_string will contain "true; then echo a; fi",
+		 * with "if " remaining in old->as_string!
+		 */
+		{
+			char *str;
+			int len = old->as_string.length;
+			/* Concatenate halves */
+			o_addstr(&old->as_string, ctx->as_string.data);
+			o_free_unsafe(&ctx->as_string);
+			/* Find where leading keyword starts in first half */
+			str = old->as_string.data + len;
+			if (str > old->as_string.data)
+				str--; /* skip whitespace after keyword */
+			while (str > old->as_string.data && isalpha(str[-1]))
+				str--;
+			/* Ugh, we're done with this horrid hack */
+			old->command->group_as_string = xstrdup(str);
+			debug_printf_parse("pop, remembering as:'%s'\n",
+					old->command->group_as_string);
+		}
 # endif
 		*ctx = *old;   /* physical copy */
 		free(old);
@@ -4248,7 +4266,7 @@ static struct pipe *parse_stream(char **pstring,
 				pi = NULL;
 			}
 #if !BB_MMU
-			debug_printf_parse("as_string '%s'\n", ctx.as_string.data);
+			debug_printf_parse("as_string1 '%s'\n", ctx.as_string.data);
 			if (pstring)
 				*pstring = ctx.as_string.data;
 			else
@@ -4399,7 +4417,7 @@ static struct pipe *parse_stream(char **pstring,
 			) {
 				o_free(&dest);
 #if !BB_MMU
-				debug_printf_parse("as_string '%s'\n", ctx.as_string.data);
+				debug_printf_parse("as_string2 '%s'\n", ctx.as_string.data);
 				if (pstring)
 					*pstring = ctx.as_string.data;
 				else
@@ -4639,9 +4657,6 @@ static struct pipe *parse_stream(char **pstring,
 				 * with redirect_opt_num(), but bash doesn't do it.
 				 * "echo foo 2| cat" yields "foo 2". */
 				done_command(&ctx);
-#if !BB_MMU
-				o_reset_to_empty_unquoted(&ctx.as_string);
-#endif
 			}
 			goto new_cmd;
 		case '(':
diff --git a/shell/hush_test/hush-misc/nommu3.right b/shell/hush_test/hush-misc/nommu3.right
new file mode 100644
index 0000000..da1534b
--- /dev/null
+++ b/shell/hush_test/hush-misc/nommu3.right
@@ -0,0 +1,2 @@
+Ok
+0
diff --git a/shell/hush_test/hush-misc/nommu3.tests b/shell/hush_test/hush-misc/nommu3.tests
new file mode 100755
index 0000000..0aca67a
--- /dev/null
+++ b/shell/hush_test/hush-misc/nommu3.tests
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+func()
+{
+	while read p; do echo "$p"; done
+}
+
+pipe_to_func()
+{
+	# We had a NOMMU bug which caused "echo Ok |" part ot be lost
+	echo Ok | func
+}
+
+pipe_to_func | cat
+echo $?


More information about the busybox-cvs mailing list