aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2018-02-08 19:19:04 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2018-02-08 19:19:04 +0100
commit5807e18f0c4f6fc247103830affcab73ca1ffa37 (patch)
tree1f67e7c1ea532803ecbcbd30b6053d3b2fd4222b
parent68ae54243cacee6beeb69842c7d562435acd5ad1 (diff)
downloadbusybox-w32-5807e18f0c4f6fc247103830affcab73ca1ffa37.tar.gz
busybox-w32-5807e18f0c4f6fc247103830affcab73ca1ffa37.tar.bz2
busybox-w32-5807e18f0c4f6fc247103830affcab73ca1ffa37.zip
hush: LINENO fix
Script triggering the bug: t=0 echo "at line ${LINENO}" while [ ${t} -lt 10 ]; do echo "at line ${LINENO}" # LINENO was 3 instead of 4 here t=$((t+1)) done function old new delta parse_stream 2754 2788 +34 done_word 711 738 +27 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/0 up/down: 61/0) Total: 61 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--shell/hush.c101
1 files changed, 77 insertions, 24 deletions
diff --git a/shell/hush.c b/shell/hush.c
index 585c51bd5..f2ffcf54d 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -120,6 +120,11 @@
120//config: help 120//config: help
121//config: Enable {abc,def} extension. 121//config: Enable {abc,def} extension.
122//config: 122//config:
123//config:config HUSH_LINENO_VAR
124//config: bool "$LINENO variable"
125//config: default y
126//config: depends on HUSH_BASH_COMPAT
127//config:
123//config:config HUSH_BASH_SOURCE_CURDIR 128//config:config HUSH_BASH_SOURCE_CURDIR
124//config: bool "'source' and '.' builtins search current directory after $PATH" 129//config: bool "'source' and '.' builtins search current directory after $PATH"
125//config: default n # do not encourage non-standard behavior 130//config: default n # do not encourage non-standard behavior
@@ -368,7 +373,6 @@
368#define BASH_SUBSTR ENABLE_HUSH_BASH_COMPAT 373#define BASH_SUBSTR ENABLE_HUSH_BASH_COMPAT
369#define BASH_SOURCE ENABLE_HUSH_BASH_COMPAT 374#define BASH_SOURCE ENABLE_HUSH_BASH_COMPAT
370#define BASH_HOSTNAME_VAR ENABLE_HUSH_BASH_COMPAT 375#define BASH_HOSTNAME_VAR ENABLE_HUSH_BASH_COMPAT
371#define BASH_LINENO_VAR ENABLE_HUSH_BASH_COMPAT
372#define BASH_TEST2 (ENABLE_HUSH_BASH_COMPAT && ENABLE_HUSH_TEST) 376#define BASH_TEST2 (ENABLE_HUSH_BASH_COMPAT && ENABLE_HUSH_TEST)
373#define BASH_READ_D ENABLE_HUSH_BASH_COMPAT 377#define BASH_READ_D ENABLE_HUSH_BASH_COMPAT
374 378
@@ -620,7 +624,7 @@ typedef enum redir_type {
620struct command { 624struct command {
621 pid_t pid; /* 0 if exited */ 625 pid_t pid; /* 0 if exited */
622 int assignment_cnt; /* how many argv[i] are assignments? */ 626 int assignment_cnt; /* how many argv[i] are assignments? */
623#if BASH_LINENO_VAR 627#if ENABLE_HUSH_LINENO_VAR
624 unsigned lineno; 628 unsigned lineno;
625#endif 629#endif
626 smallint cmd_type; /* CMD_xxx */ 630 smallint cmd_type; /* CMD_xxx */
@@ -942,7 +946,7 @@ struct globals {
942 unsigned handled_SIGCHLD; 946 unsigned handled_SIGCHLD;
943 smallint we_have_children; 947 smallint we_have_children;
944#endif 948#endif
945#if BASH_LINENO_VAR 949#if ENABLE_HUSH_LINENO_VAR
946 unsigned lineno; 950 unsigned lineno;
947 char *lineno_var; 951 char *lineno_var;
948#endif 952#endif
@@ -2152,7 +2156,7 @@ static int set_local_var(char *str, unsigned flags)
2152 } 2156 }
2153 2157
2154 name_len = eq_sign - str + 1; /* including '=' */ 2158 name_len = eq_sign - str + 1; /* including '=' */
2155#if BASH_LINENO_VAR 2159#if ENABLE_HUSH_LINENO_VAR
2156 if (G.lineno_var) { 2160 if (G.lineno_var) {
2157 if (name_len == 7 && strncmp("LINENO", str, 6) == 0) 2161 if (name_len == 7 && strncmp("LINENO", str, 6) == 0)
2158 G.lineno_var = NULL; 2162 G.lineno_var = NULL;
@@ -2285,7 +2289,7 @@ static int unset_local_var_len(const char *name, int name_len)
2285 if (name_len == 6 && strncmp(name, "OPTIND", 6) == 0) 2289 if (name_len == 6 && strncmp(name, "OPTIND", 6) == 0)
2286 G.getopt_count = 0; 2290 G.getopt_count = 0;
2287#endif 2291#endif
2288#if BASH_LINENO_VAR 2292#if ENABLE_HUSH_LINENO_VAR
2289 if (name_len == 6 && G.lineno_var && strncmp(name, "LINENO", 6) == 0) 2293 if (name_len == 6 && G.lineno_var && strncmp(name, "LINENO", 6) == 0)
2290 G.lineno_var = NULL; 2294 G.lineno_var = NULL;
2291#endif 2295#endif
@@ -2608,9 +2612,11 @@ static int i_getch(struct in_str *i)
2608 out: 2612 out:
2609 debug_printf("file_get: got '%c' %d\n", ch, ch); 2613 debug_printf("file_get: got '%c' %d\n", ch, ch);
2610 i->last_char = ch; 2614 i->last_char = ch;
2611#if BASH_LINENO_VAR 2615#if ENABLE_HUSH_LINENO_VAR
2612 if (ch == '\n') 2616 if (ch == '\n') {
2613 G.lineno++; 2617 G.lineno++;
2618 debug_printf_parse("G.lineno++ = %u\n", G.lineno);
2619 }
2614#endif 2620#endif
2615 return ch; 2621 return ch;
2616} 2622}
@@ -3412,8 +3418,13 @@ static void debug_print_tree(struct pipe *pi, int lvl)
3412 3418
3413 pin = 0; 3419 pin = 0;
3414 while (pi) { 3420 while (pi) {
3415 fdprintf(2, "%*spipe %d res_word=%s followup=%d %s\n", lvl*2, "", 3421 fdprintf(2, "%*spipe %d %sres_word=%s followup=%d %s\n",
3416 pin, RES[pi->res_word], pi->followup, PIPE[pi->followup]); 3422 lvl*2, "",
3423 pin,
3424 (IF_HAS_KEYWORDS(pi->pi_inverted ? "! " :) ""),
3425 RES[pi->res_word],
3426 pi->followup, PIPE[pi->followup]
3427 );
3417 prn = 0; 3428 prn = 0;
3418 while (prn < pi->num_cmds) { 3429 while (prn < pi->num_cmds) {
3419 struct command *command = &pi->cmds[prn]; 3430 struct command *command = &pi->cmds[prn];
@@ -3422,6 +3433,9 @@ static void debug_print_tree(struct pipe *pi, int lvl)
3422 fdprintf(2, "%*s cmd %d assignment_cnt:%d", 3433 fdprintf(2, "%*s cmd %d assignment_cnt:%d",
3423 lvl*2, "", prn, 3434 lvl*2, "", prn,
3424 command->assignment_cnt); 3435 command->assignment_cnt);
3436#if ENABLE_HUSH_LINENO_VAR
3437 fdprintf(2, " LINENO:%u", command->lineno);
3438#endif
3425 if (command->group) { 3439 if (command->group) {
3426 fdprintf(2, " group %s: (argv=%p)%s%s\n", 3440 fdprintf(2, " group %s: (argv=%p)%s%s\n",
3427 CMDTYPE[command->cmd_type], 3441 CMDTYPE[command->cmd_type],
@@ -3494,8 +3508,9 @@ static int done_command(struct parse_context *ctx)
3494 ctx->command = command = &pi->cmds[pi->num_cmds]; 3508 ctx->command = command = &pi->cmds[pi->num_cmds];
3495 clear_and_ret: 3509 clear_and_ret:
3496 memset(command, 0, sizeof(*command)); 3510 memset(command, 0, sizeof(*command));
3497#if BASH_LINENO_VAR 3511#if ENABLE_HUSH_LINENO_VAR
3498 command->lineno = G.lineno; 3512 command->lineno = G.lineno;
3513 debug_printf_parse("command->lineno = G.lineno (%u)\n", G.lineno);
3499#endif 3514#endif
3500 return pi->num_cmds; /* used only for 0/nonzero check */ 3515 return pi->num_cmds; /* used only for 0/nonzero check */
3501} 3516}
@@ -3684,9 +3699,9 @@ static const struct reserved_combo* match_reserved_word(o_string *word)
3684 } 3699 }
3685 return NULL; 3700 return NULL;
3686} 3701}
3687/* Return 0: not a keyword, 1: keyword 3702/* Return NULL: not a keyword, else: keyword
3688 */ 3703 */
3689static int reserved_word(o_string *word, struct parse_context *ctx) 3704static const struct reserved_combo* reserved_word(o_string *word, struct parse_context *ctx)
3690{ 3705{
3691# if ENABLE_HUSH_CASE 3706# if ENABLE_HUSH_CASE
3692 static const struct reserved_combo reserved_match = { 3707 static const struct reserved_combo reserved_match = {
@@ -3699,7 +3714,7 @@ static int reserved_word(o_string *word, struct parse_context *ctx)
3699 return 0; 3714 return 0;
3700 r = match_reserved_word(word); 3715 r = match_reserved_word(word);
3701 if (!r) 3716 if (!r)
3702 return 0; 3717 return r; /* NULL */
3703 3718
3704 debug_printf("found reserved word %s, res %d\n", r->literal, r->res); 3719 debug_printf("found reserved word %s, res %d\n", r->literal, r->res);
3705# if ENABLE_HUSH_CASE 3720# if ENABLE_HUSH_CASE
@@ -3714,7 +3729,7 @@ static int reserved_word(o_string *word, struct parse_context *ctx)
3714 ctx->ctx_res_w = RES_SNTX; 3729 ctx->ctx_res_w = RES_SNTX;
3715 } 3730 }
3716 ctx->ctx_inverted = 1; 3731 ctx->ctx_inverted = 1;
3717 return 1; 3732 return r;
3718 } 3733 }
3719 if (r->flag & FLAG_START) { 3734 if (r->flag & FLAG_START) {
3720 struct parse_context *old; 3735 struct parse_context *old;
@@ -3726,7 +3741,7 @@ static int reserved_word(o_string *word, struct parse_context *ctx)
3726 } else if (/*ctx->ctx_res_w == RES_NONE ||*/ !(ctx->old_flag & (1 << r->res))) { 3741 } else if (/*ctx->ctx_res_w == RES_NONE ||*/ !(ctx->old_flag & (1 << r->res))) {
3727 syntax_error_at(word->data); 3742 syntax_error_at(word->data);
3728 ctx->ctx_res_w = RES_SNTX; 3743 ctx->ctx_res_w = RES_SNTX;
3729 return 1; 3744 return r;
3730 } else { 3745 } else {
3731 /* "{...} fi" is ok. "{...} if" is not 3746 /* "{...} fi" is ok. "{...} if" is not
3732 * Example: 3747 * Example:
@@ -3776,7 +3791,7 @@ static int reserved_word(o_string *word, struct parse_context *ctx)
3776 *ctx = *old; /* physical copy */ 3791 *ctx = *old; /* physical copy */
3777 free(old); 3792 free(old);
3778 } 3793 }
3779 return 1; 3794 return r;
3780} 3795}
3781#endif /* HAS_KEYWORDS */ 3796#endif /* HAS_KEYWORDS */
3782 3797
@@ -3842,9 +3857,26 @@ static int done_word(o_string *word, struct parse_context *ctx)
3842 && ctx->ctx_res_w != RES_CASE 3857 && ctx->ctx_res_w != RES_CASE
3843# endif 3858# endif
3844 ) { 3859 ) {
3845 int reserved = reserved_word(word, ctx); 3860 const struct reserved_combo *reserved;
3846 debug_printf_parse("checking for reserved-ness: %d\n", reserved); 3861 reserved = reserved_word(word, ctx);
3862 debug_printf_parse("checking for reserved-ness: %d\n", !!reserved);
3847 if (reserved) { 3863 if (reserved) {
3864# if ENABLE_HUSH_LINENO_VAR
3865/* Case:
3866 * "while ...; do
3867 * cmd ..."
3868 * If we don't close the pipe _now_, immediately after "do", lineno logic
3869 * sees "cmd" as starting at "do" - i.e., at the previous line.
3870 */
3871 if (0
3872 IF_HUSH_IF(|| reserved->res == RES_THEN)
3873 IF_HUSH_IF(|| reserved->res == RES_ELIF)
3874 IF_HUSH_IF(|| reserved->res == RES_ELSE)
3875 IF_HUSH_LOOPS(|| reserved->res == RES_DO)
3876 ) {
3877 done_pipe(ctx, PIPE_SEQ);
3878 }
3879# endif
3848 o_reset_to_empty_unquoted(word); 3880 o_reset_to_empty_unquoted(word);
3849 debug_printf_parse("done_word return %d\n", 3881 debug_printf_parse("done_word return %d\n",
3850 (ctx->ctx_res_w == RES_SNTX)); 3882 (ctx->ctx_res_w == RES_SNTX));
@@ -4979,6 +5011,27 @@ static struct pipe *parse_stream(char **pstring,
4979 } 5011 }
4980 5012
4981 if (is_blank) { 5013 if (is_blank) {
5014#if ENABLE_HUSH_LINENO_VAR
5015/* Case:
5016 * "while ...; do<whitespace><newline>
5017 * cmd ..."
5018 * would think that "cmd" starts in <whitespace> -
5019 * i.e., at the previous line.
5020 * We need to skip all whitespace before newlines.
5021 */
5022 if (ch != '\n') {
5023 /* It was whitespace, but not a newline.
5024 * Eat all whitespace.
5025 */
5026 for (;;) {
5027 next = i_peek(input);
5028 if (next != ' ' && next != '\t' && next != '\n')
5029 break; /* next char is not ws */
5030 ch = i_getch(input);
5031 }
5032 /* ch == last eaten whitespace char */
5033 }
5034#endif
4982 if (done_word(&dest, &ctx)) { 5035 if (done_word(&dest, &ctx)) {
4983 goto parse_error; 5036 goto parse_error;
4984 } 5037 }
@@ -6573,7 +6626,7 @@ static void parse_and_run_string(const char *s)
6573static void parse_and_run_file(FILE *f) 6626static void parse_and_run_file(FILE *f)
6574{ 6627{
6575 struct in_str input; 6628 struct in_str input;
6576#if BASH_LINENO_VAR 6629#if ENABLE_HUSH_LINENO_VAR
6577 unsigned sv; 6630 unsigned sv;
6578 6631
6579 sv = G.lineno; 6632 sv = G.lineno;
@@ -6581,7 +6634,7 @@ static void parse_and_run_file(FILE *f)
6581#endif 6634#endif
6582 setup_file_in_str(&input, f); 6635 setup_file_in_str(&input, f);
6583 parse_and_run_stream(&input, ';'); 6636 parse_and_run_stream(&input, ';');
6584#if BASH_LINENO_VAR 6637#if ENABLE_HUSH_LINENO_VAR
6585 G.lineno = sv; 6638 G.lineno = sv;
6586#endif 6639#endif
6587} 6640}
@@ -8130,7 +8183,7 @@ static NOINLINE int run_pipe(struct pipe *pi)
8130 char **new_env = NULL; 8183 char **new_env = NULL;
8131 struct variable *old_vars = NULL; 8184 struct variable *old_vars = NULL;
8132 8185
8133#if BASH_LINENO_VAR 8186#if ENABLE_HUSH_LINENO_VAR
8134 if (G.lineno_var) 8187 if (G.lineno_var)
8135 strcpy(G.lineno_var + sizeof("LINENO=")-1, utoa(command->lineno)); 8188 strcpy(G.lineno_var + sizeof("LINENO=")-1, utoa(command->lineno));
8136#endif 8189#endif
@@ -8339,7 +8392,7 @@ static NOINLINE int run_pipe(struct pipe *pi)
8339 if (cmd_no < pi->num_cmds) 8392 if (cmd_no < pi->num_cmds)
8340 xpiped_pair(pipefds); 8393 xpiped_pair(pipefds);
8341 8394
8342#if BASH_LINENO_VAR 8395#if ENABLE_HUSH_LINENO_VAR
8343 if (G.lineno_var) 8396 if (G.lineno_var)
8344 strcpy(G.lineno_var + sizeof("LINENO=")-1, utoa(command->lineno)); 8397 strcpy(G.lineno_var + sizeof("LINENO=")-1, utoa(command->lineno));
8345#endif 8398#endif
@@ -9057,8 +9110,8 @@ int hush_main(int argc, char **argv)
9057 */ 9110 */
9058#endif 9111#endif
9059 9112
9060#if BASH_LINENO_VAR 9113#if ENABLE_HUSH_LINENO_VAR
9061 if (BASH_LINENO_VAR) { 9114 if (ENABLE_HUSH_LINENO_VAR) {
9062 char *p = xasprintf("LINENO=%*s", (int)(sizeof(int)*3), ""); 9115 char *p = xasprintf("LINENO=%*s", (int)(sizeof(int)*3), "");
9063 set_local_var(p, /*flags*/ 0); 9116 set_local_var(p, /*flags*/ 0);
9064 G.lineno_var = p; /* can't assign before set_local_var("LINENO=...") */ 9117 G.lineno_var = p; /* can't assign before set_local_var("LINENO=...") */