diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2011-05-14 11:27:36 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2011-05-14 11:27:36 +0200 |
commit | 29f9b7268a820505c2d9386f3271b9365dcf7e23 (patch) | |
tree | 29048a9475c582cee3cbf1f4dde08629b5940466 | |
parent | eafc558f94f75dc6132a374a15050e9d0c5c48f1 (diff) | |
download | busybox-w32-29f9b7268a820505c2d9386f3271b9365dcf7e23.tar.gz busybox-w32-29f9b7268a820505c2d9386f3271b9365dcf7e23.tar.bz2 busybox-w32-29f9b7268a820505c2d9386f3271b9365dcf7e23.zip |
hush: fix misparsing of "... do eval a= ...". Closes 3721
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | shell/hush.c | 77 | ||||
-rw-r--r-- | shell/hush_test/hush-misc/assignment4.right | 1 | ||||
-rwxr-xr-x | shell/hush_test/hush-misc/assignment4.tests | 3 |
3 files changed, 53 insertions, 28 deletions
diff --git a/shell/hush.c b/shell/hush.c index 9cc86fa9a..c3a4afb5a 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -449,6 +449,15 @@ enum { | |||
449 | /* Used for initialization: o_string foo = NULL_O_STRING; */ | 449 | /* Used for initialization: o_string foo = NULL_O_STRING; */ |
450 | #define NULL_O_STRING { NULL } | 450 | #define NULL_O_STRING { NULL } |
451 | 451 | ||
452 | #ifndef debug_printf_parse | ||
453 | static const char *const assignment_flag[] = { | ||
454 | "MAYBE_ASSIGNMENT", | ||
455 | "DEFINITELY_ASSIGNMENT", | ||
456 | "NOT_ASSIGNMENT", | ||
457 | "WORD_IS_KEYWORD", | ||
458 | }; | ||
459 | #endif | ||
460 | |||
452 | typedef struct in_str { | 461 | typedef struct in_str { |
453 | const char *p; | 462 | const char *p; |
454 | /* eof_flag=1: last char in ->p is really an EOF */ | 463 | /* eof_flag=1: last char in ->p is really an EOF */ |
@@ -3033,24 +3042,24 @@ static const struct reserved_combo* match_reserved_word(o_string *word) | |||
3033 | */ | 3042 | */ |
3034 | static const struct reserved_combo reserved_list[] = { | 3043 | static const struct reserved_combo reserved_list[] = { |
3035 | # if ENABLE_HUSH_IF | 3044 | # if ENABLE_HUSH_IF |
3036 | { "!", RES_NONE, NOT_ASSIGNMENT , 0 }, | 3045 | { "!", RES_NONE, NOT_ASSIGNMENT , 0 }, |
3037 | { "if", RES_IF, WORD_IS_KEYWORD, FLAG_THEN | FLAG_START }, | 3046 | { "if", RES_IF, MAYBE_ASSIGNMENT, FLAG_THEN | FLAG_START }, |
3038 | { "then", RES_THEN, WORD_IS_KEYWORD, FLAG_ELIF | FLAG_ELSE | FLAG_FI }, | 3047 | { "then", RES_THEN, MAYBE_ASSIGNMENT, FLAG_ELIF | FLAG_ELSE | FLAG_FI }, |
3039 | { "elif", RES_ELIF, WORD_IS_KEYWORD, FLAG_THEN }, | 3048 | { "elif", RES_ELIF, MAYBE_ASSIGNMENT, FLAG_THEN }, |
3040 | { "else", RES_ELSE, WORD_IS_KEYWORD, FLAG_FI }, | 3049 | { "else", RES_ELSE, MAYBE_ASSIGNMENT, FLAG_FI }, |
3041 | { "fi", RES_FI, NOT_ASSIGNMENT , FLAG_END }, | 3050 | { "fi", RES_FI, NOT_ASSIGNMENT , FLAG_END }, |
3042 | # endif | 3051 | # endif |
3043 | # if ENABLE_HUSH_LOOPS | 3052 | # if ENABLE_HUSH_LOOPS |
3044 | { "for", RES_FOR, NOT_ASSIGNMENT , FLAG_IN | FLAG_DO | FLAG_START }, | 3053 | { "for", RES_FOR, NOT_ASSIGNMENT , FLAG_IN | FLAG_DO | FLAG_START }, |
3045 | { "while", RES_WHILE, WORD_IS_KEYWORD, FLAG_DO | FLAG_START }, | 3054 | { "while", RES_WHILE, MAYBE_ASSIGNMENT, FLAG_DO | FLAG_START }, |
3046 | { "until", RES_UNTIL, WORD_IS_KEYWORD, FLAG_DO | FLAG_START }, | 3055 | { "until", RES_UNTIL, MAYBE_ASSIGNMENT, FLAG_DO | FLAG_START }, |
3047 | { "in", RES_IN, NOT_ASSIGNMENT , FLAG_DO }, | 3056 | { "in", RES_IN, NOT_ASSIGNMENT , FLAG_DO }, |
3048 | { "do", RES_DO, WORD_IS_KEYWORD, FLAG_DONE }, | 3057 | { "do", RES_DO, MAYBE_ASSIGNMENT, FLAG_DONE }, |
3049 | { "done", RES_DONE, NOT_ASSIGNMENT , FLAG_END }, | 3058 | { "done", RES_DONE, NOT_ASSIGNMENT , FLAG_END }, |
3050 | # endif | 3059 | # endif |
3051 | # if ENABLE_HUSH_CASE | 3060 | # if ENABLE_HUSH_CASE |
3052 | { "case", RES_CASE, NOT_ASSIGNMENT , FLAG_MATCH | FLAG_START }, | 3061 | { "case", RES_CASE, NOT_ASSIGNMENT , FLAG_MATCH | FLAG_START }, |
3053 | { "esac", RES_ESAC, NOT_ASSIGNMENT , FLAG_END }, | 3062 | { "esac", RES_ESAC, NOT_ASSIGNMENT , FLAG_END }, |
3054 | # endif | 3063 | # endif |
3055 | }; | 3064 | }; |
3056 | const struct reserved_combo *r; | 3065 | const struct reserved_combo *r; |
@@ -3116,6 +3125,7 @@ static int reserved_word(o_string *word, struct parse_context *ctx) | |||
3116 | ctx->ctx_res_w = r->res; | 3125 | ctx->ctx_res_w = r->res; |
3117 | ctx->old_flag = r->flag; | 3126 | ctx->old_flag = r->flag; |
3118 | word->o_assignment = r->assignment_flag; | 3127 | word->o_assignment = r->assignment_flag; |
3128 | debug_printf_parse("word->o_assignment='%s'\n", assignment_flag[word->o_assignment]); | ||
3119 | 3129 | ||
3120 | if (ctx->old_flag & FLAG_END) { | 3130 | if (ctx->old_flag & FLAG_END) { |
3121 | struct parse_context *old; | 3131 | struct parse_context *old; |
@@ -3182,18 +3192,6 @@ static int done_word(o_string *word, struct parse_context *ctx) | |||
3182 | debug_printf_parse("word stored in rd_filename: '%s'\n", word->data); | 3192 | debug_printf_parse("word stored in rd_filename: '%s'\n", word->data); |
3183 | ctx->pending_redirect = NULL; | 3193 | ctx->pending_redirect = NULL; |
3184 | } else { | 3194 | } else { |
3185 | /* If this word wasn't an assignment, next ones definitely | ||
3186 | * can't be assignments. Even if they look like ones. */ | ||
3187 | if (word->o_assignment != DEFINITELY_ASSIGNMENT | ||
3188 | && word->o_assignment != WORD_IS_KEYWORD | ||
3189 | ) { | ||
3190 | word->o_assignment = NOT_ASSIGNMENT; | ||
3191 | } else { | ||
3192 | if (word->o_assignment == DEFINITELY_ASSIGNMENT) | ||
3193 | command->assignment_cnt++; | ||
3194 | word->o_assignment = MAYBE_ASSIGNMENT; | ||
3195 | } | ||
3196 | |||
3197 | #if HAS_KEYWORDS | 3195 | #if HAS_KEYWORDS |
3198 | # if ENABLE_HUSH_CASE | 3196 | # if ENABLE_HUSH_CASE |
3199 | if (ctx->ctx_dsemicolon | 3197 | if (ctx->ctx_dsemicolon |
@@ -3213,8 +3211,9 @@ static int done_word(o_string *word, struct parse_context *ctx) | |||
3213 | && ctx->ctx_res_w != RES_CASE | 3211 | && ctx->ctx_res_w != RES_CASE |
3214 | # endif | 3212 | # endif |
3215 | ) { | 3213 | ) { |
3216 | debug_printf_parse("checking '%s' for reserved-ness\n", word->data); | 3214 | int reserved = reserved_word(word, ctx); |
3217 | if (reserved_word(word, ctx)) { | 3215 | debug_printf_parse("checking for reserved-ness: %d\n", reserved); |
3216 | if (reserved) { | ||
3218 | o_reset_to_empty_unquoted(word); | 3217 | o_reset_to_empty_unquoted(word); |
3219 | debug_printf_parse("done_word return %d\n", | 3218 | debug_printf_parse("done_word return %d\n", |
3220 | (ctx->ctx_res_w == RES_SNTX)); | 3219 | (ctx->ctx_res_w == RES_SNTX)); |
@@ -3235,6 +3234,23 @@ static int done_word(o_string *word, struct parse_context *ctx) | |||
3235 | "groups and arglists don't mix\n"); | 3234 | "groups and arglists don't mix\n"); |
3236 | return 1; | 3235 | return 1; |
3237 | } | 3236 | } |
3237 | |||
3238 | /* If this word wasn't an assignment, next ones definitely | ||
3239 | * can't be assignments. Even if they look like ones. */ | ||
3240 | if (word->o_assignment != DEFINITELY_ASSIGNMENT | ||
3241 | && word->o_assignment != WORD_IS_KEYWORD | ||
3242 | ) { | ||
3243 | word->o_assignment = NOT_ASSIGNMENT; | ||
3244 | } else { | ||
3245 | if (word->o_assignment == DEFINITELY_ASSIGNMENT) { | ||
3246 | command->assignment_cnt++; | ||
3247 | debug_printf_parse("++assignment_cnt=%d\n", command->assignment_cnt); | ||
3248 | } | ||
3249 | debug_printf_parse("word->o_assignment was:'%s'\n", assignment_flag[word->o_assignment]); | ||
3250 | word->o_assignment = MAYBE_ASSIGNMENT; | ||
3251 | } | ||
3252 | debug_printf_parse("word->o_assignment='%s'\n", assignment_flag[word->o_assignment]); | ||
3253 | |||
3238 | if (word->has_quoted_part | 3254 | if (word->has_quoted_part |
3239 | /* optimization: and if it's ("" or '') or ($v... or `cmd`...): */ | 3255 | /* optimization: and if it's ("" or '') or ($v... or `cmd`...): */ |
3240 | && (word->data[0] == '\0' || word->data[0] == SPECIAL_VAR_SYMBOL) | 3256 | && (word->data[0] == '\0' || word->data[0] == SPECIAL_VAR_SYMBOL) |
@@ -4259,6 +4275,7 @@ static struct pipe *parse_stream(char **pstring, | |||
4259 | && is_well_formed_var_name(dest.data, '=') | 4275 | && is_well_formed_var_name(dest.data, '=') |
4260 | ) { | 4276 | ) { |
4261 | dest.o_assignment = DEFINITELY_ASSIGNMENT; | 4277 | dest.o_assignment = DEFINITELY_ASSIGNMENT; |
4278 | debug_printf_parse("dest.o_assignment='%s'\n", assignment_flag[dest.o_assignment]); | ||
4262 | } | 4279 | } |
4263 | continue; | 4280 | continue; |
4264 | } | 4281 | } |
@@ -4308,6 +4325,7 @@ static struct pipe *parse_stream(char **pstring, | |||
4308 | heredoc_cnt = 0; | 4325 | heredoc_cnt = 0; |
4309 | } | 4326 | } |
4310 | dest.o_assignment = MAYBE_ASSIGNMENT; | 4327 | dest.o_assignment = MAYBE_ASSIGNMENT; |
4328 | debug_printf_parse("dest.o_assignment='%s'\n", assignment_flag[dest.o_assignment]); | ||
4311 | ch = ';'; | 4329 | ch = ';'; |
4312 | /* note: if (is_blank) continue; | 4330 | /* note: if (is_blank) continue; |
4313 | * will still trigger for us */ | 4331 | * will still trigger for us */ |
@@ -4357,6 +4375,7 @@ static struct pipe *parse_stream(char **pstring, | |||
4357 | } | 4375 | } |
4358 | done_pipe(&ctx, PIPE_SEQ); | 4376 | done_pipe(&ctx, PIPE_SEQ); |
4359 | dest.o_assignment = MAYBE_ASSIGNMENT; | 4377 | dest.o_assignment = MAYBE_ASSIGNMENT; |
4378 | debug_printf_parse("dest.o_assignment='%s'\n", assignment_flag[dest.o_assignment]); | ||
4360 | /* Do we sit outside of any if's, loops or case's? */ | 4379 | /* Do we sit outside of any if's, loops or case's? */ |
4361 | if (!HAS_KEYWORDS | 4380 | if (!HAS_KEYWORDS |
4362 | IF_HAS_KEYWORDS(|| (ctx.ctx_res_w == RES_NONE && ctx.old_flag == 0)) | 4381 | IF_HAS_KEYWORDS(|| (ctx.ctx_res_w == RES_NONE && ctx.old_flag == 0)) |
@@ -4463,6 +4482,7 @@ static struct pipe *parse_stream(char **pstring, | |||
4463 | /* ch is a special char and thus this word | 4482 | /* ch is a special char and thus this word |
4464 | * cannot be an assignment */ | 4483 | * cannot be an assignment */ |
4465 | dest.o_assignment = NOT_ASSIGNMENT; | 4484 | dest.o_assignment = NOT_ASSIGNMENT; |
4485 | debug_printf_parse("dest.o_assignment='%s'\n", assignment_flag[dest.o_assignment]); | ||
4466 | } | 4486 | } |
4467 | 4487 | ||
4468 | /* Note: nommu_addchr(&ctx.as_string, ch) is already done */ | 4488 | /* Note: nommu_addchr(&ctx.as_string, ch) is already done */ |
@@ -4561,6 +4581,7 @@ static struct pipe *parse_stream(char **pstring, | |||
4561 | /* We just finished a cmd. New one may start | 4581 | /* We just finished a cmd. New one may start |
4562 | * with an assignment */ | 4582 | * with an assignment */ |
4563 | dest.o_assignment = MAYBE_ASSIGNMENT; | 4583 | dest.o_assignment = MAYBE_ASSIGNMENT; |
4584 | debug_printf_parse("dest.o_assignment='%s'\n", assignment_flag[dest.o_assignment]); | ||
4564 | break; | 4585 | break; |
4565 | case '&': | 4586 | case '&': |
4566 | if (done_word(&dest, &ctx)) { | 4587 | if (done_word(&dest, &ctx)) { |
diff --git a/shell/hush_test/hush-misc/assignment4.right b/shell/hush_test/hush-misc/assignment4.right new file mode 100644 index 000000000..31c896f62 --- /dev/null +++ b/shell/hush_test/hush-misc/assignment4.right | |||
@@ -0,0 +1 @@ | |||
Done:0 | |||
diff --git a/shell/hush_test/hush-misc/assignment4.tests b/shell/hush_test/hush-misc/assignment4.tests new file mode 100755 index 000000000..6f46d0a33 --- /dev/null +++ b/shell/hush_test/hush-misc/assignment4.tests | |||
@@ -0,0 +1,3 @@ | |||
1 | # There was a bug where we misinterpreted assignments after 'do': | ||
2 | for i in 1; do eval b=; done | ||
3 | echo Done:$? | ||