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 | |
| 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>
| -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 | ||
