diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2017-08-02 19:44:05 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2017-08-02 19:46:14 +0200 |
commit | 39701204cfa0f261beb2dc056024634e4c3afd71 (patch) | |
tree | f756205f8872ed47dd06652c63fae8c83cbdeab5 /shell | |
parent | 84ea60ed65f6ea6fd3b2170e44bbff5de410a78b (diff) | |
download | busybox-w32-39701204cfa0f261beb2dc056024634e4c3afd71.tar.gz busybox-w32-39701204cfa0f261beb2dc056024634e4c3afd71.tar.bz2 busybox-w32-39701204cfa0f261beb2dc056024634e4c3afd71.zip |
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>
Diffstat (limited to 'shell')
-rw-r--r-- | shell/ash_test/ash-parsing/groups_and_keywords2.right | 3 | ||||
-rwxr-xr-x | shell/ash_test/ash-parsing/groups_and_keywords2.tests | 9 | ||||
-rw-r--r-- | shell/hush.c | 53 | ||||
-rw-r--r-- | shell/hush_test/hush-parsing/groups_and_keywords2.right | 3 | ||||
-rwxr-xr-x | shell/hush_test/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 000000000..3fcbeb662 --- /dev/null +++ b/shell/ash_test/ash-parsing/groups_and_keywords2.right | |||
@@ -0,0 +1,3 @@ | |||
1 | ./groups_and_keywords2.tests: eval: line 1: syntax error: unexpected ")" | ||
2 | Fail:2 | ||
3 | ./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 @@ | |||
1 | # This is an error | ||
2 | (eval 'if() { echo; }') | ||
3 | echo Fail:$? | ||
4 | # ^^^^^^ bash prints 1, but interactively it sets $? = 2 | ||
5 | # we print 2 | ||
6 | |||
7 | # This is an error, and it aborts in script | ||
8 | if() { echo; } | ||
9 | 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) | |||
1272 | * HUSH_DEBUG >= 2 prints line number in this file where it was detected. | 1272 | * HUSH_DEBUG >= 2 prints line number in this file where it was detected. |
1273 | */ | 1273 | */ |
1274 | #if HUSH_DEBUG < 2 | 1274 | #if HUSH_DEBUG < 2 |
1275 | # define die_if_script(lineno, ...) die_if_script(__VA_ARGS__) | 1275 | # define msg_and_die_if_script(lineno, ...) msg_and_die_if_script(__VA_ARGS__) |
1276 | # define syntax_error(lineno, msg) syntax_error(msg) | 1276 | # define syntax_error(lineno, msg) syntax_error(msg) |
1277 | # define syntax_error_at(lineno, msg) syntax_error_at(msg) | 1277 | # define syntax_error_at(lineno, msg) syntax_error_at(msg) |
1278 | # define syntax_error_unterm_ch(lineno, ch) syntax_error_unterm_ch(ch) | 1278 | # define syntax_error_unterm_ch(lineno, ch) syntax_error_unterm_ch(ch) |
@@ -1280,7 +1280,16 @@ static void xxfree(void *ptr) | |||
1280 | # define syntax_error_unexpected_ch(lineno, ch) syntax_error_unexpected_ch(ch) | 1280 | # define syntax_error_unexpected_ch(lineno, ch) syntax_error_unexpected_ch(ch) |
1281 | #endif | 1281 | #endif |
1282 | 1282 | ||
1283 | static void die_if_script(unsigned lineno, const char *fmt, ...) | 1283 | static void die_if_script(void) |
1284 | { | ||
1285 | if (!G_interactive_fd) { | ||
1286 | if (G.last_exitcode) /* sometines it's 2, not 1 (bash compat) */ | ||
1287 | xfunc_error_retval = G.last_exitcode; | ||
1288 | xfunc_die(); | ||
1289 | } | ||
1290 | } | ||
1291 | |||
1292 | static void msg_and_die_if_script(unsigned lineno, const char *fmt, ...) | ||
1284 | { | 1293 | { |
1285 | va_list p; | 1294 | va_list p; |
1286 | 1295 | ||
@@ -1290,8 +1299,7 @@ static void die_if_script(unsigned lineno, const char *fmt, ...) | |||
1290 | va_start(p, fmt); | 1299 | va_start(p, fmt); |
1291 | bb_verror_msg(fmt, p, NULL); | 1300 | bb_verror_msg(fmt, p, NULL); |
1292 | va_end(p); | 1301 | va_end(p); |
1293 | if (!G_interactive_fd) | 1302 | die_if_script(); |
1294 | xfunc_die(); | ||
1295 | } | 1303 | } |
1296 | 1304 | ||
1297 | static void syntax_error(unsigned lineno UNUSED_PARAM, const char *msg) | 1305 | 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) | |||
1300 | bb_error_msg("syntax error: %s", msg); | 1308 | bb_error_msg("syntax error: %s", msg); |
1301 | else | 1309 | else |
1302 | bb_error_msg("syntax error"); | 1310 | bb_error_msg("syntax error"); |
1311 | die_if_script(); | ||
1303 | } | 1312 | } |
1304 | 1313 | ||
1305 | static void syntax_error_at(unsigned lineno UNUSED_PARAM, const char *msg) | 1314 | static void syntax_error_at(unsigned lineno UNUSED_PARAM, const char *msg) |
1306 | { | 1315 | { |
1307 | bb_error_msg("syntax error at '%s'", msg); | 1316 | bb_error_msg("syntax error at '%s'", msg); |
1317 | die_if_script(); | ||
1308 | } | 1318 | } |
1309 | 1319 | ||
1310 | static void syntax_error_unterm_str(unsigned lineno UNUSED_PARAM, const char *s) | 1320 | static void syntax_error_unterm_str(unsigned lineno UNUSED_PARAM, const char *s) |
1311 | { | 1321 | { |
1312 | bb_error_msg("syntax error: unterminated %s", s); | 1322 | bb_error_msg("syntax error: unterminated %s", s); |
1323 | //? source4.tests fails: in bash, echo ${^} in script does not terminate the script | ||
1324 | // die_if_script(); | ||
1313 | } | 1325 | } |
1314 | 1326 | ||
1315 | static void syntax_error_unterm_ch(unsigned lineno, char ch) | 1327 | 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) | |||
1327 | bb_error_msg("hush.c:%u", lineno); | 1339 | bb_error_msg("hush.c:%u", lineno); |
1328 | #endif | 1340 | #endif |
1329 | bb_error_msg("syntax error: unexpected %s", ch == EOF ? "EOF" : msg); | 1341 | bb_error_msg("syntax error: unexpected %s", ch == EOF ? "EOF" : msg); |
1342 | die_if_script(); | ||
1330 | } | 1343 | } |
1331 | 1344 | ||
1332 | #if HUSH_DEBUG < 2 | 1345 | #if HUSH_DEBUG < 2 |
1333 | # undef die_if_script | 1346 | # undef msg_and_die_if_script |
1334 | # undef syntax_error | 1347 | # undef syntax_error |
1335 | # undef syntax_error_at | 1348 | # undef syntax_error_at |
1336 | # undef syntax_error_unterm_ch | 1349 | # undef syntax_error_unterm_ch |
1337 | # undef syntax_error_unterm_str | 1350 | # undef syntax_error_unterm_str |
1338 | # undef syntax_error_unexpected_ch | 1351 | # undef syntax_error_unexpected_ch |
1339 | #else | 1352 | #else |
1340 | # define die_if_script(...) die_if_script(__LINE__, __VA_ARGS__) | 1353 | # define msg_and_die_if_script(...) msg_and_die_if_script(__LINE__, __VA_ARGS__) |
1341 | # define syntax_error(msg) syntax_error(__LINE__, msg) | 1354 | # define syntax_error(msg) syntax_error(__LINE__, msg) |
1342 | # define syntax_error_at(msg) syntax_error_at(__LINE__, msg) | 1355 | # define syntax_error_at(msg) syntax_error_at(__LINE__, msg) |
1343 | # define syntax_error_unterm_ch(ch) syntax_error_unterm_ch(__LINE__, ch) | 1356 | # define syntax_error_unterm_ch(ch) syntax_error_unterm_ch(__LINE__, ch) |
@@ -1800,7 +1813,7 @@ static void restore_ttypgrp_and__exit(void) | |||
1800 | * echo END_OF_SCRIPT | 1813 | * echo END_OF_SCRIPT |
1801 | * lseeks fd in input FILE object from EOF to "e" in "echo END_OF_SCRIPT". | 1814 | * lseeks fd in input FILE object from EOF to "e" in "echo END_OF_SCRIPT". |
1802 | * This makes "echo END_OF_SCRIPT" executed twice. | 1815 | * This makes "echo END_OF_SCRIPT" executed twice. |
1803 | * Similar problems can be seen with die_if_script() -> xfunc_die() | 1816 | * Similar problems can be seen with msg_and_die_if_script() -> xfunc_die() |
1804 | * and in `cmd` handling. | 1817 | * and in `cmd` handling. |
1805 | * If set as die_func(), this makes xfunc_die() exit via _exit(), not exit(): | 1818 | * If set as die_func(), this makes xfunc_die() exit via _exit(), not exit(): |
1806 | */ | 1819 | */ |
@@ -3383,7 +3396,7 @@ static int done_command(struct parse_context *ctx) | |||
3383 | #if 0 /* Instead we emit error message at run time */ | 3396 | #if 0 /* Instead we emit error message at run time */ |
3384 | if (ctx->pending_redirect) { | 3397 | if (ctx->pending_redirect) { |
3385 | /* For example, "cmd >" (no filename to redirect to) */ | 3398 | /* For example, "cmd >" (no filename to redirect to) */ |
3386 | die_if_script("syntax error: %s", "invalid redirect"); | 3399 | syntax_error("invalid redirect"); |
3387 | ctx->pending_redirect = NULL; | 3400 | ctx->pending_redirect = NULL; |
3388 | } | 3401 | } |
3389 | #endif | 3402 | #endif |
@@ -3949,7 +3962,7 @@ static int parse_redirect(struct parse_context *ctx, | |||
3949 | #if 0 /* Instead we emit error message at run time */ | 3962 | #if 0 /* Instead we emit error message at run time */ |
3950 | if (ctx->pending_redirect) { | 3963 | if (ctx->pending_redirect) { |
3951 | /* For example, "cmd > <file" */ | 3964 | /* For example, "cmd > <file" */ |
3952 | die_if_script("syntax error: %s", "invalid redirect"); | 3965 | syntax_error("invalid redirect"); |
3953 | } | 3966 | } |
3954 | #endif | 3967 | #endif |
3955 | /* Set ctx->pending_redirect, so we know what to do at the | 3968 | /* Set ctx->pending_redirect, so we know what to do at the |
@@ -5021,10 +5034,16 @@ static struct pipe *parse_stream(char **pstring, | |||
5021 | else | 5034 | else |
5022 | o_free_unsafe(&ctx.as_string); | 5035 | o_free_unsafe(&ctx.as_string); |
5023 | #endif | 5036 | #endif |
5024 | debug_leave(); | 5037 | if (ch != ';' && IS_NULL_PIPE(ctx.list_head)) { |
5038 | /* Example: bare "{ }", "()" */ | ||
5039 | G.last_exitcode = 2; /* bash compat */ | ||
5040 | syntax_error_unexpected_ch(ch); | ||
5041 | goto parse_error2; | ||
5042 | } | ||
5025 | debug_printf_parse("parse_stream return %p: " | 5043 | debug_printf_parse("parse_stream return %p: " |
5026 | "end_trigger char found\n", | 5044 | "end_trigger char found\n", |
5027 | ctx.list_head); | 5045 | ctx.list_head); |
5046 | debug_leave(); | ||
5028 | return ctx.list_head; | 5047 | return ctx.list_head; |
5029 | } | 5048 | } |
5030 | } | 5049 | } |
@@ -5282,8 +5301,8 @@ static struct pipe *parse_stream(char **pstring, | |||
5282 | /* proper use of this character is caught by end_trigger: | 5301 | /* proper use of this character is caught by end_trigger: |
5283 | * if we see {, we call parse_group(..., end_trigger='}') | 5302 | * if we see {, we call parse_group(..., end_trigger='}') |
5284 | * and it will match } earlier (not here). */ | 5303 | * and it will match } earlier (not here). */ |
5285 | syntax_error_unexpected_ch(ch); | ||
5286 | G.last_exitcode = 2; | 5304 | G.last_exitcode = 2; |
5305 | syntax_error_unexpected_ch(ch); | ||
5287 | goto parse_error2; | 5306 | goto parse_error2; |
5288 | default: | 5307 | default: |
5289 | if (HUSH_DEBUG) | 5308 | if (HUSH_DEBUG) |
@@ -5513,7 +5532,7 @@ static arith_t expand_and_evaluate_arith(const char *arg, const char **errmsg_p) | |||
5513 | if (errmsg_p) | 5532 | if (errmsg_p) |
5514 | *errmsg_p = math_state.errmsg; | 5533 | *errmsg_p = math_state.errmsg; |
5515 | if (math_state.errmsg) | 5534 | if (math_state.errmsg) |
5516 | die_if_script(math_state.errmsg); | 5535 | msg_and_die_if_script(math_state.errmsg); |
5517 | return res; | 5536 | return res; |
5518 | } | 5537 | } |
5519 | #endif | 5538 | #endif |
@@ -5780,7 +5799,7 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha | |||
5780 | /* in bash, len=-n means strlen()-n */ | 5799 | /* in bash, len=-n means strlen()-n */ |
5781 | len = (arith_t)strlen(val) - beg + len; | 5800 | len = (arith_t)strlen(val) - beg + len; |
5782 | if (len < 0) /* bash compat */ | 5801 | if (len < 0) /* bash compat */ |
5783 | die_if_script("%s: substring expression < 0", var); | 5802 | msg_and_die_if_script("%s: substring expression < 0", var); |
5784 | } | 5803 | } |
5785 | if (len <= 0 || !val || beg >= strlen(val)) { | 5804 | if (len <= 0 || !val || beg >= strlen(val)) { |
5786 | arith_err: | 5805 | arith_err: |
@@ -5794,7 +5813,7 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha | |||
5794 | } | 5813 | } |
5795 | debug_printf_varexp("val:'%s'\n", val); | 5814 | debug_printf_varexp("val:'%s'\n", val); |
5796 | #else /* not (HUSH_SUBSTR_EXPANSION && FEATURE_SH_MATH) */ | 5815 | #else /* not (HUSH_SUBSTR_EXPANSION && FEATURE_SH_MATH) */ |
5797 | die_if_script("malformed ${%s:...}", var); | 5816 | msg_and_die_if_script("malformed ${%s:...}", var); |
5798 | val = NULL; | 5817 | val = NULL; |
5799 | #endif | 5818 | #endif |
5800 | } else { /* one of "-=+?" */ | 5819 | } else { /* one of "-=+?" */ |
@@ -5831,7 +5850,7 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha | |||
5831 | exp_word = to_be_freed; | 5850 | exp_word = to_be_freed; |
5832 | if (exp_op == '?') { | 5851 | if (exp_op == '?') { |
5833 | /* mimic bash message */ | 5852 | /* mimic bash message */ |
5834 | die_if_script("%s: %s", | 5853 | msg_and_die_if_script("%s: %s", |
5835 | var, | 5854 | var, |
5836 | exp_word[0] | 5855 | exp_word[0] |
5837 | ? exp_word | 5856 | ? exp_word |
@@ -5848,7 +5867,7 @@ static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, cha | |||
5848 | /* ${var=[word]} or ${var:=[word]} */ | 5867 | /* ${var=[word]} or ${var:=[word]} */ |
5849 | if (isdigit(var[0]) || var[0] == '#') { | 5868 | if (isdigit(var[0]) || var[0] == '#') { |
5850 | /* mimic bash message */ | 5869 | /* mimic bash message */ |
5851 | die_if_script("$%s: cannot assign in this way", var); | 5870 | msg_and_die_if_script("$%s: cannot assign in this way", var); |
5852 | val = NULL; | 5871 | val = NULL; |
5853 | } else { | 5872 | } else { |
5854 | char *new_var = xasprintf("%s=%s", var, val); | 5873 | char *new_var = xasprintf("%s=%s", var, val); |
@@ -6862,7 +6881,7 @@ static int setup_redirects(struct command *prog, struct squirrel **sqp) | |||
6862 | * "cmd >" (no filename) | 6881 | * "cmd >" (no filename) |
6863 | * "cmd > <file" (2nd redirect starts too early) | 6882 | * "cmd > <file" (2nd redirect starts too early) |
6864 | */ | 6883 | */ |
6865 | die_if_script("syntax error: %s", "invalid redirect"); | 6884 | syntax_error("invalid redirect"); |
6866 | continue; | 6885 | continue; |
6867 | } | 6886 | } |
6868 | mode = redir_table[redir->rd_type].mode; | 6887 | 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 @@ | |||
1 | hush: syntax error: unexpected ) | ||
2 | Fail:2 | ||
3 | 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 @@ | |||
1 | # This is an error | ||
2 | (eval 'if() { echo; }') | ||
3 | echo Fail:$? | ||
4 | # ^^^^^^ bash prints 1, but interactively it sets $? = 2 | ||
5 | # we print 2 | ||
6 | |||
7 | # This is an error, and it aborts in script | ||
8 | if() { echo; } | ||
9 | echo Not reached | ||