diff options
| author | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-08 21:51:33 +0000 |
|---|---|---|
| committer | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-08 21:51:33 +0000 |
| commit | 5c090a96f98f5a70af792945aa41ea53f82f39e2 (patch) | |
| tree | 1a95c51f459436ca1e66157a708dbb34506e732c /shell | |
| parent | ffe6f8085170ed6a9780906374ca781e9c4291cb (diff) | |
| download | busybox-w32-5c090a96f98f5a70af792945aa41ea53f82f39e2.tar.gz busybox-w32-5c090a96f98f5a70af792945aa41ea53f82f39e2.tar.bz2 busybox-w32-5c090a96f98f5a70af792945aa41ea53f82f39e2.zip | |
hush: more rodust detection of unterminated strings etc;
fix a case where we forget to copy `cmd` text;
optimize nommu heredoc helper by not passing environment to it;
add several tests
function old new delta
add_till_closing_paren 256 308 +52
parse_stream 2337 2378 +41
add_till_backquote 82 111 +29
re_execute_shell 269 284 +15
handle_dollar 802 812 +10
parse_stream_dquoted 316 320 +4
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 6/0 up/down: 151/0) Total: 151 bytes
Diffstat (limited to 'shell')
| -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 | ||
