diff options
-rw-r--r-- | shell/hush.c | 96 | ||||
-rw-r--r-- | shell/hush_test/hush-misc/heredoc_huge.right | 3 | ||||
-rwxr-xr-x | shell/hush_test/hush-misc/heredoc_huge.tests | 9 | ||||
-rw-r--r-- | shell/hush_test/hush-psubst/tick_huge.right | 3 | ||||
-rwxr-xr-x | shell/hush_test/hush-psubst/tick_huge.tests | 7 | ||||
-rw-r--r-- | shell/hush_test/hush-z_slow/leak_all2.right | 3 | ||||
-rwxr-xr-x | shell/hush_test/hush-z_slow/leak_all2.tests | 87 |
7 files changed, 177 insertions, 31 deletions
diff --git a/shell/hush.c b/shell/hush.c index 4641dca11..9920e98c6 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -2241,7 +2241,10 @@ static void re_execute_shell(const char *s, int is_heredoc) | |||
2241 | 2241 | ||
2242 | debug_printf_exec("re_execute_shell pid:%d cmd:'%s'\n", getpid(), s); | 2242 | debug_printf_exec("re_execute_shell pid:%d cmd:'%s'\n", getpid(), s); |
2243 | sigprocmask(SIG_SETMASK, &G.inherited_set, NULL); | 2243 | sigprocmask(SIG_SETMASK, &G.inherited_set, NULL); |
2244 | execv(bb_busybox_exec_path, G.argv_from_re_execing); | 2244 | execve(bb_busybox_exec_path, |
2245 | G.argv_from_re_execing, | ||
2246 | (is_heredoc ? pp /* points to NULL ptr */ : environ) | ||
2247 | ); | ||
2245 | /* Fallback. Useful for init=/bin/hush usage etc */ | 2248 | /* Fallback. Useful for init=/bin/hush usage etc */ |
2246 | if (G.argv0_for_re_execing[0] == '/') | 2249 | if (G.argv0_for_re_execing[0] == '/') |
2247 | execv(G.argv0_for_re_execing, G.argv_from_re_execing); | 2250 | execv(G.argv0_for_re_execing, G.argv_from_re_execing); |
@@ -4402,35 +4405,40 @@ static int parse_group(o_string *dest, struct parse_context *ctx, | |||
4402 | 4405 | ||
4403 | #if ENABLE_HUSH_TICK || ENABLE_SH_MATH_SUPPORT | 4406 | #if ENABLE_HUSH_TICK || ENABLE_SH_MATH_SUPPORT |
4404 | /* Subroutines for copying $(...) and `...` things */ | 4407 | /* Subroutines for copying $(...) and `...` things */ |
4405 | static void add_till_backquote(o_string *dest, struct in_str *input); | 4408 | static int add_till_backquote(o_string *dest, struct in_str *input); |
4406 | /* '...' */ | 4409 | /* '...' */ |
4407 | static void add_till_single_quote(o_string *dest, struct in_str *input) | 4410 | static int add_till_single_quote(o_string *dest, struct in_str *input) |
4408 | { | 4411 | { |
4409 | while (1) { | 4412 | while (1) { |
4410 | int ch = i_getch(input); | 4413 | int ch = i_getch(input); |
4411 | if (ch == EOF) | 4414 | if (ch == EOF) { |
4412 | break; | 4415 | syntax("unterminated '"); |
4416 | return 1; | ||
4417 | } | ||
4413 | if (ch == '\'') | 4418 | if (ch == '\'') |
4414 | break; | 4419 | return 0; |
4415 | o_addchr(dest, ch); | 4420 | o_addchr(dest, ch); |
4416 | } | 4421 | } |
4417 | } | 4422 | } |
4418 | /* "...\"...`..`...." - do we need to handle "...$(..)..." too? */ | 4423 | /* "...\"...`..`...." - do we need to handle "...$(..)..." too? */ |
4419 | static void add_till_double_quote(o_string *dest, struct in_str *input) | 4424 | static int add_till_double_quote(o_string *dest, struct in_str *input) |
4420 | { | 4425 | { |
4421 | while (1) { | 4426 | while (1) { |
4422 | int ch = i_getch(input); | 4427 | int ch = i_getch(input); |
4428 | if (ch == EOF) { | ||
4429 | syntax("unterminated \""); | ||
4430 | return 1; | ||
4431 | } | ||
4423 | if (ch == '"') | 4432 | if (ch == '"') |
4424 | break; | 4433 | return 0; |
4425 | if (ch == '\\') { /* \x. Copy both chars. */ | 4434 | if (ch == '\\') { /* \x. Copy both chars. */ |
4426 | o_addchr(dest, ch); | 4435 | o_addchr(dest, ch); |
4427 | ch = i_getch(input); | 4436 | ch = i_getch(input); |
4428 | } | 4437 | } |
4429 | if (ch == EOF) | ||
4430 | break; | ||
4431 | o_addchr(dest, ch); | 4438 | o_addchr(dest, ch); |
4432 | if (ch == '`') { | 4439 | if (ch == '`') { |
4433 | add_till_backquote(dest, input); | 4440 | if (add_till_backquote(dest, input)) |
4441 | return 1; | ||
4434 | o_addchr(dest, ch); | 4442 | o_addchr(dest, ch); |
4435 | continue; | 4443 | continue; |
4436 | } | 4444 | } |
@@ -4451,20 +4459,27 @@ static void add_till_double_quote(o_string *dest, struct in_str *input) | |||
4451 | * Example Output | 4459 | * Example Output |
4452 | * echo `echo '\'TEST\`echo ZZ\`BEST` \TESTZZBEST | 4460 | * echo `echo '\'TEST\`echo ZZ\`BEST` \TESTZZBEST |
4453 | */ | 4461 | */ |
4454 | static void add_till_backquote(o_string *dest, struct in_str *input) | 4462 | static int add_till_backquote(o_string *dest, struct in_str *input) |
4455 | { | 4463 | { |
4456 | while (1) { | 4464 | while (1) { |
4457 | int ch = i_getch(input); | 4465 | int ch = i_getch(input); |
4466 | if (ch == EOF) { | ||
4467 | syntax("unterminated `"); | ||
4468 | return 1; | ||
4469 | } | ||
4458 | if (ch == '`') | 4470 | if (ch == '`') |
4459 | break; | 4471 | return 0; |
4460 | if (ch == '\\') { /* \x. Copy both chars unless it is \` */ | 4472 | if (ch == '\\') { |
4473 | /* \x. Copy both chars unless it is \` */ | ||
4461 | int ch2 = i_getch(input); | 4474 | int ch2 = i_getch(input); |
4475 | if (ch2 == EOF) { | ||
4476 | syntax("unterminated `"); | ||
4477 | return 1; | ||
4478 | } | ||
4462 | if (ch2 != '`' && ch2 != '$' && ch2 != '\\') | 4479 | if (ch2 != '`' && ch2 != '$' && ch2 != '\\') |
4463 | o_addchr(dest, ch); | 4480 | o_addchr(dest, ch); |
4464 | ch = ch2; | 4481 | ch = ch2; |
4465 | } | 4482 | } |
4466 | if (ch == EOF) | ||
4467 | break; | ||
4468 | o_addchr(dest, ch); | 4483 | o_addchr(dest, ch); |
4469 | } | 4484 | } |
4470 | } | 4485 | } |
@@ -4480,13 +4495,15 @@ static void add_till_backquote(o_string *dest, struct in_str *input) | |||
4480 | * echo $(echo 'TEST)' BEST) TEST) BEST | 4495 | * echo $(echo 'TEST)' BEST) TEST) BEST |
4481 | * echo $(echo \(\(TEST\) BEST) ((TEST) BEST | 4496 | * echo $(echo \(\(TEST\) BEST) ((TEST) BEST |
4482 | */ | 4497 | */ |
4483 | static void add_till_closing_paren(o_string *dest, struct in_str *input, bool dbl) | 4498 | static int add_till_closing_paren(o_string *dest, struct in_str *input, bool dbl) |
4484 | { | 4499 | { |
4485 | int count = 0; | 4500 | int count = 0; |
4486 | while (1) { | 4501 | while (1) { |
4487 | int ch = i_getch(input); | 4502 | int ch = i_getch(input); |
4488 | if (ch == EOF) | 4503 | if (ch == EOF) { |
4489 | break; | 4504 | syntax("unterminated )"); |
4505 | return 1; | ||
4506 | } | ||
4490 | if (ch == '(') | 4507 | if (ch == '(') |
4491 | count++; | 4508 | count++; |
4492 | if (ch == ')') { | 4509 | if (ch == ')') { |
@@ -4501,23 +4518,29 @@ static void add_till_closing_paren(o_string *dest, struct in_str *input, bool db | |||
4501 | } | 4518 | } |
4502 | o_addchr(dest, ch); | 4519 | o_addchr(dest, ch); |
4503 | if (ch == '\'') { | 4520 | if (ch == '\'') { |
4504 | add_till_single_quote(dest, input); | 4521 | if (add_till_single_quote(dest, input)) |
4522 | return 1; | ||
4505 | o_addchr(dest, ch); | 4523 | o_addchr(dest, ch); |
4506 | continue; | 4524 | continue; |
4507 | } | 4525 | } |
4508 | if (ch == '"') { | 4526 | if (ch == '"') { |
4509 | add_till_double_quote(dest, input); | 4527 | if (add_till_double_quote(dest, input)) |
4528 | return 1; | ||
4510 | o_addchr(dest, ch); | 4529 | o_addchr(dest, ch); |
4511 | continue; | 4530 | continue; |
4512 | } | 4531 | } |
4513 | if (ch == '\\') { /* \x. Copy verbatim. Important for \(, \) */ | 4532 | if (ch == '\\') { |
4533 | /* \x. Copy verbatim. Important for \(, \) */ | ||
4514 | ch = i_getch(input); | 4534 | ch = i_getch(input); |
4515 | if (ch == EOF) | 4535 | if (ch == EOF) { |
4516 | break; | 4536 | syntax("unterminated )"); |
4537 | return 1; | ||
4538 | } | ||
4517 | o_addchr(dest, ch); | 4539 | o_addchr(dest, ch); |
4518 | continue; | 4540 | continue; |
4519 | } | 4541 | } |
4520 | } | 4542 | } |
4543 | return 0; | ||
4521 | } | 4544 | } |
4522 | #endif /* ENABLE_HUSH_TICK || ENABLE_SH_MATH_SUPPORT */ | 4545 | #endif /* ENABLE_HUSH_TICK || ENABLE_SH_MATH_SUPPORT */ |
4523 | 4546 | ||
@@ -4658,7 +4681,8 @@ static int handle_dollar(o_string *as_string, | |||
4658 | # if !BB_MMU | 4681 | # if !BB_MMU |
4659 | pos = dest->length; | 4682 | pos = dest->length; |
4660 | # endif | 4683 | # endif |
4661 | add_till_closing_paren(dest, input, true); | 4684 | if (add_till_closing_paren(dest, input, true)) |
4685 | return 1; | ||
4662 | # if !BB_MMU | 4686 | # if !BB_MMU |
4663 | if (as_string) { | 4687 | if (as_string) { |
4664 | o_addstr(as_string, dest->data + pos); | 4688 | o_addstr(as_string, dest->data + pos); |
@@ -4671,20 +4695,19 @@ static int handle_dollar(o_string *as_string, | |||
4671 | } | 4695 | } |
4672 | # endif | 4696 | # endif |
4673 | # if ENABLE_HUSH_TICK | 4697 | # if ENABLE_HUSH_TICK |
4674 | //int pos = dest->length; | ||
4675 | o_addchr(dest, SPECIAL_VAR_SYMBOL); | 4698 | o_addchr(dest, SPECIAL_VAR_SYMBOL); |
4676 | o_addchr(dest, quote_mask | '`'); | 4699 | o_addchr(dest, quote_mask | '`'); |
4677 | # if !BB_MMU | 4700 | # if !BB_MMU |
4678 | pos = dest->length; | 4701 | pos = dest->length; |
4679 | # endif | 4702 | # endif |
4680 | add_till_closing_paren(dest, input, false); | 4703 | if (add_till_closing_paren(dest, input, false)) |
4704 | return 1; | ||
4681 | # if !BB_MMU | 4705 | # if !BB_MMU |
4682 | if (as_string) { | 4706 | if (as_string) { |
4683 | o_addstr(as_string, dest->data + pos); | 4707 | o_addstr(as_string, dest->data + pos); |
4684 | o_addchr(as_string, '`'); | 4708 | o_addchr(as_string, '`'); |
4685 | } | 4709 | } |
4686 | # endif | 4710 | # endif |
4687 | //debug_printf_subst("SUBST RES2 '%s'\n", dest->data + pos); | ||
4688 | o_addchr(dest, SPECIAL_VAR_SYMBOL); | 4711 | o_addchr(dest, SPECIAL_VAR_SYMBOL); |
4689 | # endif | 4712 | # endif |
4690 | break; | 4713 | break; |
@@ -4778,7 +4801,8 @@ static int parse_stream_dquoted(o_string *as_string, | |||
4778 | //int pos = dest->length; | 4801 | //int pos = dest->length; |
4779 | o_addchr(dest, SPECIAL_VAR_SYMBOL); | 4802 | o_addchr(dest, SPECIAL_VAR_SYMBOL); |
4780 | o_addchr(dest, 0x80 | '`'); | 4803 | o_addchr(dest, 0x80 | '`'); |
4781 | add_till_backquote(dest, input); | 4804 | if (add_till_backquote(dest, input)) |
4805 | return 1; | ||
4782 | o_addchr(dest, SPECIAL_VAR_SYMBOL); | 4806 | o_addchr(dest, SPECIAL_VAR_SYMBOL); |
4783 | //debug_printf_subst("SUBST RES3 '%s'\n", dest->data + pos); | 4807 | //debug_printf_subst("SUBST RES3 '%s'\n", dest->data + pos); |
4784 | goto again; | 4808 | goto again; |
@@ -5043,10 +5067,20 @@ static struct pipe *parse_stream(char **pstring, | |||
5043 | break; | 5067 | break; |
5044 | #if ENABLE_HUSH_TICK | 5068 | #if ENABLE_HUSH_TICK |
5045 | case '`': { | 5069 | case '`': { |
5046 | //int pos = dest.length; | 5070 | #if !BB_MMU |
5071 | int pos; | ||
5072 | #endif | ||
5047 | o_addchr(&dest, SPECIAL_VAR_SYMBOL); | 5073 | o_addchr(&dest, SPECIAL_VAR_SYMBOL); |
5048 | o_addchr(&dest, '`'); | 5074 | o_addchr(&dest, '`'); |
5049 | add_till_backquote(&dest, input); | 5075 | #if !BB_MMU |
5076 | pos = dest.length; | ||
5077 | #endif | ||
5078 | if (add_till_backquote(&dest, input)) | ||
5079 | goto parse_error; | ||
5080 | #if !BB_MMU | ||
5081 | o_addstr(&ctx.as_string, dest.data + pos); | ||
5082 | o_addchr(&ctx.as_string, '`'); | ||
5083 | #endif | ||
5050 | o_addchr(&dest, SPECIAL_VAR_SYMBOL); | 5084 | o_addchr(&dest, SPECIAL_VAR_SYMBOL); |
5051 | //debug_printf_subst("SUBST RES3 '%s'\n", dest.data + pos); | 5085 | //debug_printf_subst("SUBST RES3 '%s'\n", dest.data + pos); |
5052 | break; | 5086 | break; |
diff --git a/shell/hush_test/hush-misc/heredoc_huge.right b/shell/hush_test/hush-misc/heredoc_huge.right new file mode 100644 index 000000000..11740f674 --- /dev/null +++ b/shell/hush_test/hush-misc/heredoc_huge.right | |||
@@ -0,0 +1,3 @@ | |||
1 | 546ed3f5c81c780d3ab86ada14824237 - | ||
2 | 546ed3f5c81c780d3ab86ada14824237 - | ||
3 | End | ||
diff --git a/shell/hush_test/hush-misc/heredoc_huge.tests b/shell/hush_test/hush-misc/heredoc_huge.tests new file mode 100755 index 000000000..c2ec2817b --- /dev/null +++ b/shell/hush_test/hush-misc/heredoc_huge.tests | |||
@@ -0,0 +1,9 @@ | |||
1 | # This creates 120k heredoc | ||
2 | echo 'cat <<HERE | md5sum' >"$0.tmp" | ||
3 | yes "123456789 123456789 123456789 123456789" | head -3000 >>"$0.tmp" | ||
4 | echo 'HERE' >>"$0.tmp" | ||
5 | |||
6 | yes "123456789 123456789 123456789 123456789" | head -3000 | md5sum | ||
7 | . "$0.tmp" | ||
8 | rm "$0.tmp" | ||
9 | echo End | ||
diff --git a/shell/hush_test/hush-psubst/tick_huge.right b/shell/hush_test/hush-psubst/tick_huge.right new file mode 100644 index 000000000..11740f674 --- /dev/null +++ b/shell/hush_test/hush-psubst/tick_huge.right | |||
@@ -0,0 +1,3 @@ | |||
1 | 546ed3f5c81c780d3ab86ada14824237 - | ||
2 | 546ed3f5c81c780d3ab86ada14824237 - | ||
3 | End | ||
diff --git a/shell/hush_test/hush-psubst/tick_huge.tests b/shell/hush_test/hush-psubst/tick_huge.tests new file mode 100755 index 000000000..acce92fb2 --- /dev/null +++ b/shell/hush_test/hush-psubst/tick_huge.tests | |||
@@ -0,0 +1,7 @@ | |||
1 | # This creates 120k file | ||
2 | yes "123456789 123456789 123456789 123456789" | head -3000 >>"$0.tmp" | ||
3 | |||
4 | echo "`cat $0.tmp`" | md5sum | ||
5 | rm "$0.tmp" | ||
6 | yes "123456789 123456789 123456789 123456789" | head -3000 | md5sum | ||
7 | echo End | ||
diff --git a/shell/hush_test/hush-z_slow/leak_all2.right b/shell/hush_test/hush-z_slow/leak_all2.right new file mode 100644 index 000000000..c6f0334f3 --- /dev/null +++ b/shell/hush_test/hush-z_slow/leak_all2.right | |||
@@ -0,0 +1,3 @@ | |||
1 | Warm up | ||
2 | Measuring memory leak... | ||
3 | Ok | ||
diff --git a/shell/hush_test/hush-z_slow/leak_all2.tests b/shell/hush_test/hush-z_slow/leak_all2.tests new file mode 100755 index 000000000..8fb1ca9b4 --- /dev/null +++ b/shell/hush_test/hush-z_slow/leak_all2.tests | |||
@@ -0,0 +1,87 @@ | |||
1 | # "Check many leaks" test #2 | ||
2 | # Cramming all kinds of weird commands in here. | ||
3 | # As you find leaks, please create separate, small test | ||
4 | # for each leak. | ||
5 | # Narrowing down the leak using this large test may be difficult. | ||
6 | # It is intended to be a blanket "is everything ok?" test | ||
7 | |||
8 | echo "Warm up" | ||
9 | local_var="local val" | ||
10 | export dev_null="/dev/null" | ||
11 | >$dev_null | ||
12 | echo hi1 $local_var `echo ho` >>/dev/null | ||
13 | echo hi2 $local_var </dev/null | echo 2>&- | cat 1<>/dev/null | ||
14 | { echo hi4 $local_var `echo ho` 1<>/dev/null; } | ||
15 | ( echo hi4 $local_var `echo ho` 1<>/dev/null ) | ||
16 | if echo $local_var; false | ||
17 | then echo not run | ||
18 | elif false <$dev_null | ||
19 | then none | ||
20 | else cat 0<>$dev_null 1<>"$dev_null" | ||
21 | fi >>/dev/null | ||
22 | { | ||
23 | if echo $local_var; then cat <<HERE | ||
24 | Hi cat | ||
25 | HERE | ||
26 | fi >>/dev/null | ||
27 | } 1<>/dev/null | ||
28 | while { echo $dev_null >>$dev_null; }; do cat <"$dev_null"; break; done | ||
29 | ( until { echo $dev_null >>$dev_null | false; }; do cat <"$dev_null"; break; done ) <$dev_null | ||
30 | |||
31 | memleak | ||
32 | |||
33 | echo "Measuring memory leak..." | ||
34 | # Please copy the entire block from above verbatim | ||
35 | local_var="local val" | ||
36 | export dev_null="/dev/null" | ||
37 | >$dev_null | ||
38 | echo hi1 $local_var `echo ho` >>/dev/null | ||
39 | echo hi2 $local_var </dev/null | echo 2>&- | cat 1<>/dev/null | ||
40 | { echo hi4 $local_var `echo ho` 1<>/dev/null; } | ||
41 | ( echo hi4 $local_var `echo ho` 1<>/dev/null ) | ||
42 | if echo $local_var; false | ||
43 | then echo not run | ||
44 | elif false <$dev_null | ||
45 | then none | ||
46 | else cat 0<>$dev_null 1<>"$dev_null" | ||
47 | fi >>/dev/null | ||
48 | { | ||
49 | if echo $local_var; then cat <<HERE | ||
50 | Hi cat | ||
51 | HERE | ||
52 | fi >>/dev/null | ||
53 | } 1<>/dev/null | ||
54 | while { echo $dev_null >>$dev_null; }; do cat <"$dev_null"; break; done | ||
55 | ( until { echo $dev_null >>$dev_null | false; }; do cat <"$dev_null"; break; done ) <$dev_null | ||
56 | |||
57 | # And same again | ||
58 | |||
59 | local_var="local val" | ||
60 | export dev_null="/dev/null" | ||
61 | >$dev_null | ||
62 | echo hi1 $local_var `echo ho` >>/dev/null | ||
63 | echo hi2 $local_var </dev/null | echo 2>&- | cat 1<>/dev/null | ||
64 | { echo hi4 $local_var `echo ho` 1<>/dev/null; } | ||
65 | ( echo hi4 $local_var `echo ho` 1<>/dev/null ) | ||
66 | if echo $local_var; false | ||
67 | then echo not run | ||
68 | elif false <$dev_null | ||
69 | then none | ||
70 | else cat 0<>$dev_null 1<>"$dev_null" | ||
71 | fi >>/dev/null | ||
72 | { | ||
73 | if echo $local_var; then cat <<HERE | ||
74 | Hi cat | ||
75 | HERE | ||
76 | fi >>/dev/null | ||
77 | } 1<>/dev/null | ||
78 | while { echo $dev_null >>$dev_null; }; do cat <"$dev_null"; break; done | ||
79 | ( until { echo $dev_null >>$dev_null | false; }; do cat <"$dev_null"; break; done ) <$dev_null | ||
80 | |||
81 | memleak | ||
82 | kb=$? | ||
83 | if test $kb -le 4; then | ||
84 | echo Ok #$kb | ||
85 | else | ||
86 | echo "Bad: $kb kb (or more) leaked" | ||
87 | fi | ||