[git commit] hush: do not accept "if() { echo; }" function def

Denys Vlasenko vda.linux at googlemail.com
Wed Aug 2 17:46:14 UTC 2017


commit: https://git.busybox.net/busybox/commit/?id=39701204cfa0f261beb2dc056024634e4c3afd71
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/master

function                                             old     new   delta
parse_stream                                        2634    2692     +58
msg_and_die_if_script                                  -      21     +21
syntax_error_unexpected_ch                            41      46      +5
syntax_error_at                                       14      18      +4
die_if_script                                         31      28      -3
setup_redirects                                      319     308     -11
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 3/2 up/down: 88/-14)             Total: 74 bytes

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 .../ash-parsing/groups_and_keywords2.right         |  3 ++
 .../ash-parsing/groups_and_keywords2.tests         |  9 ++++
 shell/hush.c                                       | 53 +++++++++++++++-------
 .../hush-parsing/groups_and_keywords2.right        |  3 ++
 .../hush-parsing/groups_and_keywords2.tests        |  9 ++++
 5 files changed, 60 insertions(+), 17 deletions(-)

diff --git a/shell/ash_test/ash-parsing/groups_and_keywords2.right b/shell/ash_test/ash-parsing/groups_and_keywords2.right
new file mode 100644
index 0000000..3fcbeb6
--- /dev/null
+++ b/shell/ash_test/ash-parsing/groups_and_keywords2.right
@@ -0,0 +1,3 @@
+./groups_and_keywords2.tests: eval: line 1: syntax error: unexpected ")"
+Fail:2
+./groups_and_keywords2.tests: line 8: syntax error: unexpected ")"
diff --git a/shell/ash_test/ash-parsing/groups_and_keywords2.tests b/shell/ash_test/ash-parsing/groups_and_keywords2.tests
new file mode 100755
index 0000000..ab33b90
--- /dev/null
+++ b/shell/ash_test/ash-parsing/groups_and_keywords2.tests
@@ -0,0 +1,9 @@
+# This is an error
+(eval 'if() { echo; }')
+echo Fail:$?
+# ^^^^^^ bash prints 1, but interactively it sets $? = 2
+# we print 2
+
+# This is an error, and it aborts in script
+if() { echo; }
+echo Not reached
diff --git a/shell/hush.c b/shell/hush.c
index 6fa4e16..b04f793 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -1272,7 +1272,7 @@ static void xxfree(void *ptr)
  * HUSH_DEBUG >= 2 prints line number in this file where it was detected.
  */
 #if HUSH_DEBUG < 2
-# define die_if_script(lineno, ...)             die_if_script(__VA_ARGS__)
+# define msg_and_die_if_script(lineno, ...)     msg_and_die_if_script(__VA_ARGS__)
 # define syntax_error(lineno, msg)              syntax_error(msg)
 # define syntax_error_at(lineno, msg)           syntax_error_at(msg)
 # define syntax_error_unterm_ch(lineno, ch)     syntax_error_unterm_ch(ch)
@@ -1280,7 +1280,16 @@ static void xxfree(void *ptr)
 # define syntax_error_unexpected_ch(lineno, ch) syntax_error_unexpected_ch(ch)
 #endif
 
-static void die_if_script(unsigned lineno, const char *fmt, ...)
+static void die_if_script(void)
+{
+	if (!G_interactive_fd) {
+		if (G.last_exitcode) /* sometines it's 2, not 1 (bash compat) */
+			xfunc_error_retval = G.last_exitcode;
+		xfunc_die();
+	}
+}
+
+static void msg_and_die_if_script(unsigned lineno, const char *fmt, ...)
 {
 	va_list p;
 
@@ -1290,8 +1299,7 @@ static void die_if_script(unsigned lineno, const char *fmt, ...)
 	va_start(p, fmt);
 	bb_verror_msg(fmt, p, NULL);
 	va_end(p);
-	if (!G_interactive_fd)
-		xfunc_die();
+	die_if_script();
 }
 
 static void syntax_error(unsigned lineno UNUSED_PARAM, const char *msg)
@@ -1300,16 +1308,20 @@ static void syntax_error(unsigned lineno UNUSED_PARAM, const char *msg)
 		bb_error_msg("syntax error: %s", msg);
 	else
 		bb_error_msg("syntax error");
+	die_if_script();
 }
 
 static void syntax_error_at(unsigned lineno UNUSED_PARAM, const char *msg)
 {
 	bb_error_msg("syntax error at '%s'", msg);
+	die_if_script();
 }
 
 static void syntax_error_unterm_str(unsigned lineno UNUSED_PARAM, const char *s)
 {
 	bb_error_msg("syntax error: unterminated %s", s);
+//? source4.tests fails: in bash, echo ${^} in script does not terminate the script
+//	die_if_script();
 }
 
 static void syntax_error_unterm_ch(unsigned lineno, char ch)
@@ -1327,17 +1339,18 @@ static void syntax_error_unexpected_ch(unsigned lineno UNUSED_PARAM, int ch)
 	bb_error_msg("hush.c:%u", lineno);
 #endif
 	bb_error_msg("syntax error: unexpected %s", ch == EOF ? "EOF" : msg);
+	die_if_script();
 }
 
 #if HUSH_DEBUG < 2
-# undef die_if_script
+# undef msg_and_die_if_script
 # undef syntax_error
 # undef syntax_error_at
 # undef syntax_error_unterm_ch
 # undef syntax_error_unterm_str
 # undef syntax_error_unexpected_ch
 #else
-# define die_if_script(...)             die_if_script(__LINE__, __VA_ARGS__)
+# define msg_and_die_if_script(...)     msg_and_die_if_script(__LINE__, __VA_ARGS__)
 # define syntax_error(msg)              syntax_error(__LINE__, msg)
 # define syntax_error_at(msg)           syntax_error_at(__LINE__, msg)
 # define syntax_error_unterm_ch(ch)     syntax_error_unterm_ch(__LINE__, ch)
@@ -1800,7 +1813,7 @@ static void restore_ttypgrp_and__exit(void)
  *	echo END_OF_SCRIPT
  * lseeks fd in input FILE object from EOF to "e" in "echo END_OF_SCRIPT".
  * This makes "echo END_OF_SCRIPT" executed twice.
- * Similar problems can be seen with die_if_script() -> xfunc_die()
+ * Similar problems can be seen with msg_and_die_if_script() -> xfunc_die()
  * and in `cmd` handling.
  * If set as die_func(), this makes xfunc_die() exit via _exit(), not exit():
  */
@@ -3383,7 +3396,7 @@ static int done_command(struct parse_context *ctx)
 #if 0	/* Instead we emit error message at run time */
 	if (ctx->pending_redirect) {
 		/* For example, "cmd >" (no filename to redirect to) */
-		die_if_script("syntax error: %s", "invalid redirect");
+		syntax_error("invalid redirect");
 		ctx->pending_redirect = NULL;
 	}
 #endif
@@ -3949,7 +3962,7 @@ static int parse_redirect(struct parse_context *ctx,
 #if 0		/* Instead we emit error message at run time */
 		if (ctx->pending_redirect) {
 			/* For example, "cmd > <file" */
-			die_if_script("syntax error: %s", "invalid redirect");
+			syntax_error("invalid redirect");
 		}
 #endif
 		/* Set ctx->pending_redirect, so we know what to do at the
@@ -5021,10 +5034,16 @@ static struct pipe *parse_stream(char **pstring,
 				else
 					o_free_unsafe(&ctx.as_string);
 #endif
-				debug_leave();
+				if (ch != ';' && IS_NULL_PIPE(ctx.list_head)) {
+					/* Example: bare "{ }", "()" */
+					G.last_exitcode = 2; /* bash compat */
+					syntax_error_unexpected_ch(ch);
+					goto parse_error2;
+				}
 				debug_printf_parse("parse_stream return %p: "
 						"end_trigger char found\n",
 						ctx.list_head);
+				debug_leave();
 				return ctx.list_head;
 			}
 		}
@@ -5282,8 +5301,8 @@ static struct pipe *parse_stream(char **pstring,
 			/* proper use of this character is caught by end_trigger:
 			 * if we see {, we call parse_group(..., end_trigger='}')
 			 * and it will match } earlier (not here). */
-			syntax_error_unexpected_ch(ch);
 			G.last_exitcode = 2;
+			syntax_error_unexpected_ch(ch);
 			goto parse_error2;
 		default:
 			if (HUSH_DEBUG)
@@ -5513,7 +5532,7 @@ static arith_t expand_and_evaluate_arith(const char *arg, const char **errmsg_p)
 	if (errmsg_p)
 		*errmsg_p = math_state.errmsg;
 	if (math_state.errmsg)
-		die_if_script(math_state.errmsg);
+		msg_and_die_if_script(math_state.errmsg);
 	return res;
 }
 #endif
@@ -5780,7 +5799,7 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha
 				/* in bash, len=-n means strlen()-n */
 				len = (arith_t)strlen(val) - beg + len;
 				if (len < 0) /* bash compat */
-					die_if_script("%s: substring expression < 0", var);
+					msg_and_die_if_script("%s: substring expression < 0", var);
 			}
 			if (len <= 0 || !val || beg >= strlen(val)) {
  arith_err:
@@ -5794,7 +5813,7 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha
 			}
 			debug_printf_varexp("val:'%s'\n", val);
 #else /* not (HUSH_SUBSTR_EXPANSION && FEATURE_SH_MATH) */
-			die_if_script("malformed ${%s:...}", var);
+			msg_and_die_if_script("malformed ${%s:...}", var);
 			val = NULL;
 #endif
 		} else { /* one of "-=+?" */
@@ -5831,7 +5850,7 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha
 					exp_word = to_be_freed;
 				if (exp_op == '?') {
 					/* mimic bash message */
-					die_if_script("%s: %s",
+					msg_and_die_if_script("%s: %s",
 						var,
 						exp_word[0]
 						? exp_word
@@ -5848,7 +5867,7 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha
 					/* ${var=[word]} or ${var:=[word]} */
 					if (isdigit(var[0]) || var[0] == '#') {
 						/* mimic bash message */
-						die_if_script("$%s: cannot assign in this way", var);
+						msg_and_die_if_script("$%s: cannot assign in this way", var);
 						val = NULL;
 					} else {
 						char *new_var = xasprintf("%s=%s", var, val);
@@ -6862,7 +6881,7 @@ static int setup_redirects(struct command *prog, struct squirrel **sqp)
 				 * "cmd >" (no filename)
 				 * "cmd > <file" (2nd redirect starts too early)
 				 */
-				die_if_script("syntax error: %s", "invalid redirect");
+				syntax_error("invalid redirect");
 				continue;
 			}
 			mode = redir_table[redir->rd_type].mode;
diff --git a/shell/hush_test/hush-parsing/groups_and_keywords2.right b/shell/hush_test/hush-parsing/groups_and_keywords2.right
new file mode 100644
index 0000000..ae74a5d
--- /dev/null
+++ b/shell/hush_test/hush-parsing/groups_and_keywords2.right
@@ -0,0 +1,3 @@
+hush: syntax error: unexpected )
+Fail:2
+hush: syntax error: unexpected )
diff --git a/shell/hush_test/hush-parsing/groups_and_keywords2.tests b/shell/hush_test/hush-parsing/groups_and_keywords2.tests
new file mode 100755
index 0000000..ab33b90
--- /dev/null
+++ b/shell/hush_test/hush-parsing/groups_and_keywords2.tests
@@ -0,0 +1,9 @@
+# This is an error
+(eval 'if() { echo; }')
+echo Fail:$?
+# ^^^^^^ bash prints 1, but interactively it sets $? = 2
+# we print 2
+
+# This is an error, and it aborts in script
+if() { echo; }
+echo Not reached


More information about the busybox-cvs mailing list