aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2018-07-24 13:03:03 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2018-07-24 13:03:03 +0200
commit474cb205554919e4d017b7aeb3722d6a4ffee41d (patch)
treea6934231956c3f3756b3d78750a83cdddf746b85
parent3675c37b9b0bb4ba565b690b95b0b9c7d0ce8123 (diff)
downloadbusybox-w32-474cb205554919e4d017b7aeb3722d6a4ffee41d.tar.gz
busybox-w32-474cb205554919e4d017b7aeb3722d6a4ffee41d.tar.bz2
busybox-w32-474cb205554919e4d017b7aeb3722d6a4ffee41d.zip
hush: fix handling of heredocs not enclosed in groups where they are "declared"
function old new delta fetch_heredocs - 479 +479 parse_and_run_stream 146 148 +2 parse_stream 2787 2296 -491 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 1/1 up/down: 481/-491) Total: -10 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--shell/ash_test/ash-heredoc/heredoc_after_compound1.right2
-rwxr-xr-xshell/ash_test/ash-heredoc/heredoc_after_compound1.tests3
-rw-r--r--shell/hush.c104
-rw-r--r--shell/hush_test/hush-heredoc/heredoc_after_compound1.right2
-rwxr-xr-xshell/hush_test/hush-heredoc/heredoc_after_compound1.tests3
-rw-r--r--shell/hush_test/hush-heredoc/heredoc_var_expand1.right4
-rwxr-xr-xshell/hush_test/hush-heredoc/heredoc_var_expand1.tests11
7 files changed, 84 insertions, 45 deletions
diff --git a/shell/ash_test/ash-heredoc/heredoc_after_compound1.right b/shell/ash_test/ash-heredoc/heredoc_after_compound1.right
new file mode 100644
index 000000000..9052f7d1f
--- /dev/null
+++ b/shell/ash_test/ash-heredoc/heredoc_after_compound1.right
@@ -0,0 +1,2 @@
1Ok1
2Ok2
diff --git a/shell/ash_test/ash-heredoc/heredoc_after_compound1.tests b/shell/ash_test/ash-heredoc/heredoc_after_compound1.tests
new file mode 100755
index 000000000..e7cfb5be1
--- /dev/null
+++ b/shell/ash_test/ash-heredoc/heredoc_after_compound1.tests
@@ -0,0 +1,3 @@
1{ cat <<EOF; }; echo Ok2
2Ok1
3EOF
diff --git a/shell/hush.c b/shell/hush.c
index 130c8e958..75bce337a 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -3534,6 +3534,8 @@ static void debug_print_tree(struct pipe *pi, int lvl)
3534 fdprintf(2, " '%s'", *argv); 3534 fdprintf(2, " '%s'", *argv);
3535 argv++; 3535 argv++;
3536 } 3536 }
3537 if (command->redirects)
3538 fdprintf(2, " {redir}");
3537 fdprintf(2, "\n"); 3539 fdprintf(2, "\n");
3538 prn++; 3540 prn++;
3539 } 3541 }
@@ -4292,10 +4294,12 @@ static char *fetch_till_str(o_string *as_string,
4292/* Look at entire parse tree for not-yet-loaded REDIRECT_HEREDOCs 4294/* Look at entire parse tree for not-yet-loaded REDIRECT_HEREDOCs
4293 * and load them all. There should be exactly heredoc_cnt of them. 4295 * and load them all. There should be exactly heredoc_cnt of them.
4294 */ 4296 */
4295static int fetch_heredocs(int heredoc_cnt, struct parse_context *ctx, struct in_str *input) 4297#if BB_MMU
4298#define fetch_heredocs(as_string, pi, heredoc_cnt, input) \
4299 fetch_heredocs(pi, heredoc_cnt, input)
4300#endif
4301static int fetch_heredocs(o_string *as_string, struct pipe *pi, int heredoc_cnt, struct in_str *input)
4296{ 4302{
4297 struct pipe *pi = ctx->list_head;
4298
4299 while (pi && heredoc_cnt) { 4303 while (pi && heredoc_cnt) {
4300 int i; 4304 int i;
4301 struct command *cmd = pi->cmds; 4305 struct command *cmd = pi->cmds;
@@ -4315,11 +4319,11 @@ static int fetch_heredocs(int heredoc_cnt, struct parse_context *ctx, struct in_
4315 4319
4316 redir->rd_type = REDIRECT_HEREDOC2; 4320 redir->rd_type = REDIRECT_HEREDOC2;
4317 /* redir->rd_dup is (ab)used to indicate <<- */ 4321 /* redir->rd_dup is (ab)used to indicate <<- */
4318 p = fetch_till_str(&ctx->as_string, input, 4322 p = fetch_till_str(as_string, input,
4319 redir->rd_filename, redir->rd_dup); 4323 redir->rd_filename, redir->rd_dup);
4320 if (!p) { 4324 if (!p) {
4321 syntax_error("unexpected EOF in here document"); 4325 syntax_error("unexpected EOF in here document");
4322 return 1; 4326 return -1;
4323 } 4327 }
4324 free(redir->rd_filename); 4328 free(redir->rd_filename);
4325 redir->rd_filename = p; 4329 redir->rd_filename = p;
@@ -4327,29 +4331,36 @@ static int fetch_heredocs(int heredoc_cnt, struct parse_context *ctx, struct in_
4327 } 4331 }
4328 redir = redir->next; 4332 redir = redir->next;
4329 } 4333 }
4334 if (cmd->group) {
4335 //bb_error_msg("%s:%u heredoc_cnt:%d", __func__, __LINE__, heredoc_cnt);
4336 heredoc_cnt = fetch_heredocs(as_string, cmd->group, heredoc_cnt, input);
4337 //bb_error_msg("%s:%u heredoc_cnt:%d", __func__, __LINE__, heredoc_cnt);
4338 if (heredoc_cnt < 0)
4339 return heredoc_cnt; /* error */
4340 }
4330 cmd++; 4341 cmd++;
4331 } 4342 }
4332 pi = pi->next; 4343 pi = pi->next;
4333 } 4344 }
4334 /* Should be 0. If it isn't, it's a parse error */ 4345 return heredoc_cnt;
4335 if (HUSH_DEBUG && heredoc_cnt)
4336 bb_error_msg_and_die("heredoc BUG 2");
4337 return 0;
4338} 4346}
4339 4347
4340 4348
4341static int run_list(struct pipe *pi); 4349static int run_list(struct pipe *pi);
4342#if BB_MMU 4350#if BB_MMU
4343#define parse_stream(pstring, input, end_trigger) \ 4351#define parse_stream(pstring, heredoc_cnt_ptr, input, end_trigger) \
4344 parse_stream(input, end_trigger) 4352 parse_stream(heredoc_cnt_ptr, input, end_trigger)
4345#endif 4353#endif
4346static struct pipe *parse_stream(char **pstring, 4354static struct pipe *parse_stream(char **pstring,
4355 int *heredoc_cnt_ptr,
4347 struct in_str *input, 4356 struct in_str *input,
4348 int end_trigger); 4357 int end_trigger);
4349 4358
4350 4359/* Returns number of heredocs not yet consumed,
4360 * or -1 on error.
4361 */
4351static int parse_group(struct parse_context *ctx, 4362static int parse_group(struct parse_context *ctx,
4352 struct in_str *input, int ch) 4363 struct in_str *input, int ch)
4353{ 4364{
4354 /* ctx->word contains characters seen prior to ( or {. 4365 /* ctx->word contains characters seen prior to ( or {.
4355 * Typically it's empty, but for function defs, 4366 * Typically it's empty, but for function defs,
@@ -4360,6 +4371,7 @@ static int parse_group(struct parse_context *ctx,
4360 char *as_string = NULL; 4371 char *as_string = NULL;
4361#endif 4372#endif
4362 struct pipe *pipe_list; 4373 struct pipe *pipe_list;
4374 int heredoc_cnt = 0;
4363 int endch; 4375 int endch;
4364 struct command *command = ctx->command; 4376 struct command *command = ctx->command;
4365 4377
@@ -4368,12 +4380,12 @@ static int parse_group(struct parse_context *ctx,
4368 if (ch == '(' && !ctx->word.has_quoted_part) { 4380 if (ch == '(' && !ctx->word.has_quoted_part) {
4369 if (ctx->word.length) 4381 if (ctx->word.length)
4370 if (done_word(ctx)) 4382 if (done_word(ctx))
4371 return 1; 4383 return -1;
4372 if (!command->argv) 4384 if (!command->argv)
4373 goto skip; /* (... */ 4385 goto skip; /* (... */
4374 if (command->argv[1]) { /* word word ... (... */ 4386 if (command->argv[1]) { /* word word ... (... */
4375 syntax_error_unexpected_ch('('); 4387 syntax_error_unexpected_ch('(');
4376 return 1; 4388 return -1;
4377 } 4389 }
4378 /* it is "word(..." or "word (..." */ 4390 /* it is "word(..." or "word (..." */
4379 do 4391 do
@@ -4381,7 +4393,7 @@ static int parse_group(struct parse_context *ctx,
4381 while (ch == ' ' || ch == '\t'); 4393 while (ch == ' ' || ch == '\t');
4382 if (ch != ')') { 4394 if (ch != ')') {
4383 syntax_error_unexpected_ch(ch); 4395 syntax_error_unexpected_ch(ch);
4384 return 1; 4396 return -1;
4385 } 4397 }
4386 nommu_addchr(&ctx->as_string, ch); 4398 nommu_addchr(&ctx->as_string, ch);
4387 do 4399 do
@@ -4389,7 +4401,7 @@ static int parse_group(struct parse_context *ctx,
4389 while (ch == ' ' || ch == '\t' || ch == '\n'); 4401 while (ch == ' ' || ch == '\t' || ch == '\n');
4390 if (ch != '{' && ch != '(') { 4402 if (ch != '{' && ch != '(') {
4391 syntax_error_unexpected_ch(ch); 4403 syntax_error_unexpected_ch(ch);
4392 return 1; 4404 return -1;
4393 } 4405 }
4394 nommu_addchr(&ctx->as_string, ch); 4406 nommu_addchr(&ctx->as_string, ch);
4395 command->cmd_type = CMD_FUNCDEF; 4407 command->cmd_type = CMD_FUNCDEF;
@@ -4403,9 +4415,9 @@ static int parse_group(struct parse_context *ctx,
4403 || ctx->word.has_quoted_part /* ""{... */ 4415 || ctx->word.has_quoted_part /* ""{... */
4404 ) { 4416 ) {
4405 syntax_error(NULL); 4417 syntax_error(NULL);
4406 debug_printf_parse("parse_group return 1: " 4418 debug_printf_parse("parse_group return -1: "
4407 "syntax error, groups and arglists don't mix\n"); 4419 "syntax error, groups and arglists don't mix\n");
4408 return 1; 4420 return -1;
4409 } 4421 }
4410#endif 4422#endif
4411 4423
@@ -4423,7 +4435,7 @@ static int parse_group(struct parse_context *ctx,
4423 && ch != '(' /* but "{(..." is allowed (without whitespace) */ 4435 && ch != '(' /* but "{(..." is allowed (without whitespace) */
4424 ) { 4436 ) {
4425 syntax_error_unexpected_ch(ch); 4437 syntax_error_unexpected_ch(ch);
4426 return 1; 4438 return -1;
4427 } 4439 }
4428 if (ch != '(') { 4440 if (ch != '(') {
4429 ch = i_getch(input); 4441 ch = i_getch(input);
@@ -4431,7 +4443,9 @@ static int parse_group(struct parse_context *ctx,
4431 } 4443 }
4432 } 4444 }
4433 4445
4434 pipe_list = parse_stream(&as_string, input, endch); 4446 debug_printf_heredoc("calling parse_stream, heredoc_cnt:%d\n", heredoc_cnt);
4447 pipe_list = parse_stream(&as_string, &heredoc_cnt, input, endch);
4448 debug_printf_heredoc("parse_stream returned: heredoc_cnt:%d\n", heredoc_cnt);
4435#if !BB_MMU 4449#if !BB_MMU
4436 if (as_string) 4450 if (as_string)
4437 o_addstr(&ctx->as_string, as_string); 4451 o_addstr(&ctx->as_string, as_string);
@@ -4442,9 +4456,9 @@ static int parse_group(struct parse_context *ctx,
4442 /* parse_stream already emitted error msg */ 4456 /* parse_stream already emitted error msg */
4443 if (!BB_MMU) 4457 if (!BB_MMU)
4444 free(as_string); 4458 free(as_string);
4445 debug_printf_parse("parse_group return 1: " 4459 debug_printf_parse("parse_group return -1: "
4446 "parse_stream returned %p\n", pipe_list); 4460 "parse_stream returned %p\n", pipe_list);
4447 return 1; 4461 return -1;
4448 } 4462 }
4449#if !BB_MMU 4463#if !BB_MMU
4450 as_string[strlen(as_string) - 1] = '\0'; /* plink ')' or '}' */ 4464 as_string[strlen(as_string) - 1] = '\0'; /* plink ')' or '}' */
@@ -4475,8 +4489,8 @@ static int parse_group(struct parse_context *ctx,
4475 4489
4476 command->group = pipe_list; 4490 command->group = pipe_list;
4477 4491
4478 debug_printf_parse("parse_group return 0\n"); 4492 debug_printf_parse("parse_group return %d\n", heredoc_cnt);
4479 return 0; 4493 return heredoc_cnt;
4480 /* command remains "open", available for possible redirects */ 4494 /* command remains "open", available for possible redirects */
4481#undef as_string 4495#undef as_string
4482} 4496}
@@ -5002,6 +5016,7 @@ static int encode_string(o_string *as_string,
5002 * or return ERR_PTR. 5016 * or return ERR_PTR.
5003 */ 5017 */
5004static struct pipe *parse_stream(char **pstring, 5018static struct pipe *parse_stream(char **pstring,
5019 int *heredoc_cnt_ptr,
5005 struct in_str *input, 5020 struct in_str *input,
5006 int end_trigger) 5021 int end_trigger)
5007{ 5022{
@@ -5077,7 +5092,11 @@ static struct pipe *parse_stream(char **pstring,
5077 else 5092 else
5078 o_free(&ctx.as_string); 5093 o_free(&ctx.as_string);
5079#endif 5094#endif
5095 // heredoc_cnt must be 0 here anyway
5096 //if (heredoc_cnt_ptr)
5097 // *heredoc_cnt_ptr = heredoc_cnt;
5080 debug_leave(); 5098 debug_leave();
5099 debug_printf_heredoc("parse_stream return heredoc_cnt:%d\n", heredoc_cnt);
5081 debug_printf_parse("parse_stream return %p\n", pi); 5100 debug_printf_parse("parse_stream return %p\n", pi);
5082 return pi; 5101 return pi;
5083 } 5102 }
@@ -5236,10 +5255,9 @@ static struct pipe *parse_stream(char **pstring,
5236 done_pipe(&ctx, PIPE_SEQ); 5255 done_pipe(&ctx, PIPE_SEQ);
5237 debug_printf_heredoc("heredoc_cnt:%d\n", heredoc_cnt); 5256 debug_printf_heredoc("heredoc_cnt:%d\n", heredoc_cnt);
5238 if (heredoc_cnt) { 5257 if (heredoc_cnt) {
5239 if (fetch_heredocs(heredoc_cnt, &ctx, input)) { 5258 heredoc_cnt = fetch_heredocs(&ctx.as_string, ctx.list_head, heredoc_cnt, input);
5259 if (heredoc_cnt != 0)
5240 goto parse_error; 5260 goto parse_error;
5241 }
5242 heredoc_cnt = 0;
5243 } 5261 }
5244 ctx.is_assignment = MAYBE_ASSIGNMENT; 5262 ctx.is_assignment = MAYBE_ASSIGNMENT;
5245 debug_printf_parse("ctx.is_assignment='%s'\n", assignment_flag[ctx.is_assignment]); 5263 debug_printf_parse("ctx.is_assignment='%s'\n", assignment_flag[ctx.is_assignment]);
@@ -5288,19 +5306,6 @@ static struct pipe *parse_stream(char **pstring,
5288 ) 5306 )
5289#endif 5307#endif
5290 ) { 5308 ) {
5291 if (heredoc_cnt) {
5292 /* This is technically valid:
5293 * { cat <<HERE; }; echo Ok
5294 * heredoc
5295 * heredoc
5296 * HERE
5297 * but we don't support this.
5298 * We require heredoc to be in enclosing {}/(),
5299 * if any.
5300 */
5301 syntax_error_unterm_str("here document");
5302 goto parse_error;
5303 }
5304 if (done_word(&ctx)) { 5309 if (done_word(&ctx)) {
5305 goto parse_error; 5310 goto parse_error;
5306 } 5311 }
@@ -5325,6 +5330,9 @@ static struct pipe *parse_stream(char **pstring,
5325 syntax_error_unexpected_ch(ch); 5330 syntax_error_unexpected_ch(ch);
5326 goto parse_error2; 5331 goto parse_error2;
5327 } 5332 }
5333 if (heredoc_cnt_ptr)
5334 *heredoc_cnt_ptr = heredoc_cnt;
5335 debug_printf_heredoc("parse_stream return heredoc_cnt:%d\n", heredoc_cnt);
5328 debug_printf_parse("parse_stream return %p: " 5336 debug_printf_parse("parse_stream return %p: "
5329 "end_trigger char found\n", 5337 "end_trigger char found\n",
5330 ctx.list_head); 5338 ctx.list_head);
@@ -5546,16 +5554,22 @@ static struct pipe *parse_stream(char **pstring,
5546 continue; /* get next char */ 5554 continue; /* get next char */
5547 } 5555 }
5548#endif 5556#endif
5549 case '{': 5557 /* fall through */
5550 if (parse_group(&ctx, input, ch) != 0) { 5558 case '{': {
5559 int n = parse_group(&ctx, input, ch);
5560 if (n < 0) {
5551 goto parse_error; 5561 goto parse_error;
5552 } 5562 }
5563 debug_printf_heredoc("parse_group done, needs heredocs:%d\n", n);
5564 heredoc_cnt += n;
5553 goto new_cmd; 5565 goto new_cmd;
5566 }
5554 case ')': 5567 case ')':
5555#if ENABLE_HUSH_CASE 5568#if ENABLE_HUSH_CASE
5556 if (ctx.ctx_res_w == RES_MATCH) 5569 if (ctx.ctx_res_w == RES_MATCH)
5557 goto case_semi; 5570 goto case_semi;
5558#endif 5571#endif
5572
5559 case '}': 5573 case '}':
5560 /* proper use of this character is caught by end_trigger: 5574 /* proper use of this character is caught by end_trigger:
5561 * if we see {, we call parse_group(..., end_trigger='}') 5575 * if we see {, we call parse_group(..., end_trigger='}')
@@ -5604,7 +5618,7 @@ static struct pipe *parse_stream(char **pstring,
5604 IF_HAS_KEYWORDS(pctx = p2;) 5618 IF_HAS_KEYWORDS(pctx = p2;)
5605 } while (HAS_KEYWORDS && pctx); 5619 } while (HAS_KEYWORDS && pctx);
5606 5620
5607 o_free_and_set_NULL(&ctx.word); 5621 o_free(&ctx.word);
5608#if !BB_MMU 5622#if !BB_MMU
5609 if (pstring) 5623 if (pstring)
5610 *pstring = NULL; 5624 *pstring = NULL;
@@ -7035,7 +7049,7 @@ static void parse_and_run_stream(struct in_str *inp, int end_trigger)
7035 debug_printf_prompt("%s promptmode=%d\n", __func__, G.promptmode); 7049 debug_printf_prompt("%s promptmode=%d\n", __func__, G.promptmode);
7036 } 7050 }
7037#endif 7051#endif
7038 pipe_list = parse_stream(NULL, inp, end_trigger); 7052 pipe_list = parse_stream(NULL, NULL, inp, end_trigger);
7039 if (!pipe_list || pipe_list == ERR_PTR) { /* EOF/error */ 7053 if (!pipe_list || pipe_list == ERR_PTR) { /* EOF/error */
7040 /* If we are in "big" script 7054 /* If we are in "big" script
7041 * (not in `cmd` or something similar)... 7055 * (not in `cmd` or something similar)...
diff --git a/shell/hush_test/hush-heredoc/heredoc_after_compound1.right b/shell/hush_test/hush-heredoc/heredoc_after_compound1.right
new file mode 100644
index 000000000..9052f7d1f
--- /dev/null
+++ b/shell/hush_test/hush-heredoc/heredoc_after_compound1.right
@@ -0,0 +1,2 @@
1Ok1
2Ok2
diff --git a/shell/hush_test/hush-heredoc/heredoc_after_compound1.tests b/shell/hush_test/hush-heredoc/heredoc_after_compound1.tests
new file mode 100755
index 000000000..e7cfb5be1
--- /dev/null
+++ b/shell/hush_test/hush-heredoc/heredoc_after_compound1.tests
@@ -0,0 +1,3 @@
1{ cat <<EOF; }; echo Ok2
2Ok1
3EOF
diff --git a/shell/hush_test/hush-heredoc/heredoc_var_expand1.right b/shell/hush_test/hush-heredoc/heredoc_var_expand1.right
new file mode 100644
index 000000000..eb221832d
--- /dev/null
+++ b/shell/hush_test/hush-heredoc/heredoc_var_expand1.right
@@ -0,0 +1,4 @@
1
2Ok1:0
3
4Ok2:0
diff --git a/shell/hush_test/hush-heredoc/heredoc_var_expand1.tests b/shell/hush_test/hush-heredoc/heredoc_var_expand1.tests
new file mode 100755
index 000000000..3b00bab7b
--- /dev/null
+++ b/shell/hush_test/hush-heredoc/heredoc_var_expand1.tests
@@ -0,0 +1,11 @@
1x='*'
2
3cat <<- EOF
4 ${x#'*'}
5EOF
6echo Ok1:$?
7
8cat <<EOF
9${x#'*'}
10EOF
11echo Ok2:$?