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>
This commit is contained in:
parent
84ea60ed65
commit
39701204cf
3
shell/ash_test/ash-parsing/groups_and_keywords2.right
Normal file
3
shell/ash_test/ash-parsing/groups_and_keywords2.right
Normal file
@ -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 ")"
|
9
shell/ash_test/ash-parsing/groups_and_keywords2.tests
Executable file
9
shell/ash_test/ash-parsing/groups_and_keywords2.tests
Executable file
@ -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
|
53
shell/hush.c
53
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;
|
||||
|
3
shell/hush_test/hush-parsing/groups_and_keywords2.right
Normal file
3
shell/hush_test/hush-parsing/groups_and_keywords2.right
Normal file
@ -0,0 +1,3 @@
|
||||
hush: syntax error: unexpected )
|
||||
Fail:2
|
||||
hush: syntax error: unexpected )
|
9
shell/hush_test/hush-parsing/groups_and_keywords2.tests
Executable file
9
shell/hush_test/hush-parsing/groups_and_keywords2.tests
Executable file
@ -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
|
Loading…
Reference in New Issue
Block a user