summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2017-08-02 19:44:05 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2017-08-02 19:46:14 +0200
commit39701204cfa0f261beb2dc056024634e4c3afd71 (patch)
treef756205f8872ed47dd06652c63fae8c83cbdeab5
parent84ea60ed65f6ea6fd3b2170e44bbff5de410a78b (diff)
hush: do not accept "if() { echo; }" function def
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@googlemail.com>
-rw-r--r--shell/ash_test/ash-parsing/groups_and_keywords2.right3
-rwxr-xr-xshell/ash_test/ash-parsing/groups_and_keywords2.tests9
-rw-r--r--shell/hush.c53
-rw-r--r--shell/hush_test/hush-parsing/groups_and_keywords2.right3
-rwxr-xr-xshell/hush_test/hush-parsing/groups_and_keywords2.tests9
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 000000000..3fcbeb662
--- /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 000000000..ab33b909f
--- /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 6fa4e1630..b04f793f1 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 000000000..ae74a5db9
--- /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 000000000..ab33b909f
--- /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