aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2011-05-14 11:27:36 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2011-05-14 11:27:36 +0200
commit29f9b7268a820505c2d9386f3271b9365dcf7e23 (patch)
tree29048a9475c582cee3cbf1f4dde08629b5940466
parenteafc558f94f75dc6132a374a15050e9d0c5c48f1 (diff)
downloadbusybox-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.c77
-rw-r--r--shell/hush_test/hush-misc/assignment4.right1
-rwxr-xr-xshell/hush_test/hush-misc/assignment4.tests3
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
453static const char *const assignment_flag[] = {
454 "MAYBE_ASSIGNMENT",
455 "DEFINITELY_ASSIGNMENT",
456 "NOT_ASSIGNMENT",
457 "WORD_IS_KEYWORD",
458};
459#endif
460
452typedef struct in_str { 461typedef 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':
2for i in 1; do eval b=; done
3echo Done:$?