diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-10-09 16:29:44 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-10-09 16:29:44 +0000 |
commit | afd7a8d744b29daaedbba1969307bd9ce17e7dc3 (patch) | |
tree | 015fa25e84f72a32b31724add0969f51a03bb74d | |
parent | 07e05c100fe6ac2bc5aa3505daabb55224c06a1f (diff) | |
download | busybox-w32-afd7a8d744b29daaedbba1969307bd9ce17e7dc3.tar.gz busybox-w32-afd7a8d744b29daaedbba1969307bd9ce17e7dc3.tar.bz2 busybox-w32-afd7a8d744b29daaedbba1969307bd9ce17e7dc3.zip |
hush: fix environment and memory leaks, add tests for them
function old new delta
add_malloced_string_to_strings - 110 +110
run_list 1999 2086 +87
free_strings_and_unsetenv - 87 +87
hush_version_str - 18 +18
pseudo_exec_argv 139 146 +7
static.version_str 17 - -17
free_pipe 237 210 -27
done_word 790 642 -148
------------------------------------------------------------------------------
(add/remove: 3/1 grow/shrink: 2/2 up/down: 309/-192) Total: 117 bytes
-rw-r--r-- | shell/hush.c | 149 | ||||
-rw-r--r-- | shell/hush_test/hush-vars/var_leaks.right | 1 | ||||
-rwxr-xr-x | shell/hush_test/hush-vars/var_leaks.tests | 14 | ||||
-rwxr-xr-x | shell/hush_test/hush-z_slow/leak_var.tests | 47 | ||||
-rw-r--r-- | shell/hush_test/hush-z_slow/leak_var2.right | 2 | ||||
-rwxr-xr-x | shell/hush_test/hush-z_slow/leak_var2.tests | 63 |
6 files changed, 218 insertions, 58 deletions
diff --git a/shell/hush.c b/shell/hush.c index d5955dd93..7cf2f3322 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -54,7 +54,7 @@ | |||
54 | * port selected bugfixes from post-0.49 busybox lash - done? | 54 | * port selected bugfixes from post-0.49 busybox lash - done? |
55 | * change { and } from special chars to reserved words | 55 | * change { and } from special chars to reserved words |
56 | * builtins: return, trap, ulimit | 56 | * builtins: return, trap, ulimit |
57 | * test magic exec | 57 | * test magic exec with redirection only |
58 | * check setting of global_argc and global_argv | 58 | * check setting of global_argc and global_argv |
59 | * follow IFS rules more precisely, including update semantics | 59 | * follow IFS rules more precisely, including update semantics |
60 | * figure out what to do with backslash-newline | 60 | * figure out what to do with backslash-newline |
@@ -73,7 +73,7 @@ | |||
73 | #include <fnmatch.h> | 73 | #include <fnmatch.h> |
74 | #endif | 74 | #endif |
75 | 75 | ||
76 | #define HUSH_VER_STR "0.9" | 76 | #define HUSH_VER_STR "0.91" |
77 | 77 | ||
78 | #if !BB_MMU && ENABLE_HUSH_TICK | 78 | #if !BB_MMU && ENABLE_HUSH_TICK |
79 | //#undef ENABLE_HUSH_TICK | 79 | //#undef ENABLE_HUSH_TICK |
@@ -525,13 +525,13 @@ static int free_pipe(struct pipe *pi, int indent); | |||
525 | static int setup_redirects(struct command *prog, int squirrel[]); | 525 | static int setup_redirects(struct command *prog, int squirrel[]); |
526 | static int run_list(struct pipe *pi); | 526 | static int run_list(struct pipe *pi); |
527 | #if BB_MMU | 527 | #if BB_MMU |
528 | #define pseudo_exec_argv(ptrs2free, argv, assignment_cnt, argv_expanded) \ | 528 | #define pseudo_exec_argv(ptr_ptrs2free, argv, assignment_cnt, argv_expanded) \ |
529 | pseudo_exec_argv(argv, assignment_cnt, argv_expanded) | 529 | pseudo_exec_argv(argv, assignment_cnt, argv_expanded) |
530 | #define pseudo_exec(ptrs2free, command, argv_expanded) \ | 530 | #define pseudo_exec(ptr_ptrs2free, command, argv_expanded) \ |
531 | pseudo_exec(command, argv_expanded) | 531 | pseudo_exec(command, argv_expanded) |
532 | #endif | 532 | #endif |
533 | static void pseudo_exec_argv(char **ptrs2free, char **argv, int assignment_cnt, char **argv_expanded) NORETURN; | 533 | static void pseudo_exec_argv(char ***ptr_ptrs2free, char **argv, int assignment_cnt, char **argv_expanded) NORETURN; |
534 | static void pseudo_exec(char **ptrs2free, struct command *command, char **argv_expanded) NORETURN; | 534 | static void pseudo_exec(char ***ptr_ptrs2free, struct command *command, char **argv_expanded) NORETURN; |
535 | static int run_pipe(struct pipe *pi); | 535 | static int run_pipe(struct pipe *pi); |
536 | /* data structure manipulation: */ | 536 | /* data structure manipulation: */ |
537 | static int setup_redirect(struct parse_context *ctx, int fd, redir_type style, struct in_str *input); | 537 | static int setup_redirect(struct parse_context *ctx, int fd, redir_type style, struct in_str *input); |
@@ -576,6 +576,9 @@ static int set_local_var(char *str, int flg_export); | |||
576 | static void unset_local_var(const char *name); | 576 | static void unset_local_var(const char *name); |
577 | 577 | ||
578 | 578 | ||
579 | static const char hush_version_str[] ALIGN1 = "HUSH_VERSION="HUSH_VER_STR; | ||
580 | |||
581 | |||
579 | static int glob_needed(const char *s) | 582 | static int glob_needed(const char *s) |
580 | { | 583 | { |
581 | while (*s) { | 584 | while (*s) { |
@@ -650,26 +653,44 @@ static char **add_malloced_string_to_strings(char **strings, char *add) | |||
650 | return add_malloced_strings_to_strings(strings, v); | 653 | return add_malloced_strings_to_strings(strings, v); |
651 | } | 654 | } |
652 | 655 | ||
653 | static void free_strings(char **strings) | 656 | static void free_strings_and_unsetenv(char **strings, int unset) |
654 | { | 657 | { |
655 | if (strings) { | 658 | char **v; |
656 | char **v = strings; | 659 | |
657 | while (*v) | 660 | if (!strings) |
658 | free(*v++); | 661 | return; |
659 | free(strings); | 662 | |
663 | v = strings; | ||
664 | while (*v) { | ||
665 | if (unset) { | ||
666 | char *copy; | ||
667 | #if !BB_MMU | ||
668 | /* If this is a magic guard pointer, do not free it, | ||
669 | * and stop unsetting */ | ||
670 | if (*v == hush_version_str) { | ||
671 | unset = 0; | ||
672 | v++; | ||
673 | continue; | ||
674 | } | ||
675 | #endif | ||
676 | /* *strchrnul(*v, '=') = '\0'; -- BAD | ||
677 | * In case *v was putenv'ed, we can't | ||
678 | * unsetenv(*v) after taking out '=': | ||
679 | * it won't work, env is modified by taking out! | ||
680 | * horror :( */ | ||
681 | copy = xstrndup(*v, strchrnul(*v, '=') - *v); | ||
682 | unsetenv(copy); | ||
683 | free(copy); | ||
684 | } | ||
685 | free(*v++); | ||
660 | } | 686 | } |
687 | free(strings); | ||
661 | } | 688 | } |
662 | 689 | ||
663 | #if !BB_MMU | 690 | static void free_strings(char **strings) |
664 | #define EXTRA_PTRS 5 /* 1 for NULL, 1 for args, 3 for paranoid reasons */ | ||
665 | static char **alloc_ptrs(char **argv) | ||
666 | { | 691 | { |
667 | char **v = argv; | 692 | free_strings_and_unsetenv(strings, 0); |
668 | while (*v) | ||
669 | v++; | ||
670 | return xzalloc((v - argv + EXTRA_PTRS) * sizeof(v[0])); | ||
671 | } | 693 | } |
672 | #endif | ||
673 | 694 | ||
674 | 695 | ||
675 | /* Function prototypes for builtins */ | 696 | /* Function prototypes for builtins */ |
@@ -1393,34 +1414,36 @@ static void restore_redirects(int squirrel[]) | |||
1393 | * XXX no exit() here. If you don't exec, use _exit instead. | 1414 | * XXX no exit() here. If you don't exec, use _exit instead. |
1394 | * The at_exit handlers apparently confuse the calling process, | 1415 | * The at_exit handlers apparently confuse the calling process, |
1395 | * in particular stdin handling. Not sure why? -- because of vfork! (vda) */ | 1416 | * in particular stdin handling. Not sure why? -- because of vfork! (vda) */ |
1396 | static void pseudo_exec_argv(char **ptrs2free, char **argv, int assignment_cnt, char **argv_expanded) | 1417 | static void pseudo_exec_argv(char ***ptr_ptrs2free, char **argv, int assignment_cnt, char **argv_expanded) |
1397 | { | 1418 | { |
1398 | int i, rcode; | 1419 | int i, rcode; |
1399 | char *p; | 1420 | char *p; |
1400 | const struct built_in_command *x; | 1421 | const struct built_in_command *x; |
1401 | 1422 | ||
1402 | for (i = 0; i < assignment_cnt; i++) { | ||
1403 | debug_printf_exec("pid %d environment modification: %s\n", | ||
1404 | getpid(), argv[i]); | ||
1405 | p = expand_string_to_string(argv[i]); | ||
1406 | #if !BB_MMU | ||
1407 | *ptrs2free++ = p; | ||
1408 | #endif | ||
1409 | putenv(p); | ||
1410 | } | ||
1411 | argv += i; | ||
1412 | /* If a variable is assigned in a forest, and nobody listens, | 1423 | /* If a variable is assigned in a forest, and nobody listens, |
1413 | * was it ever really set? | 1424 | * was it ever really set? |
1414 | */ | 1425 | */ |
1415 | if (!argv[0]) | 1426 | if (!argv[assignment_cnt]) |
1416 | _exit(EXIT_SUCCESS); | 1427 | _exit(EXIT_SUCCESS); |
1417 | 1428 | ||
1429 | for (i = 0; i < assignment_cnt; i++) { | ||
1430 | debug_printf_exec("pid %d environment modification: %s\n", | ||
1431 | getpid(), *argv); | ||
1432 | p = expand_string_to_string(*argv); | ||
1433 | putenv(p); | ||
1434 | #if !BB_MMU | ||
1435 | *ptr_ptrs2free = add_malloced_string_to_strings(*ptr_ptrs2free, p); | ||
1436 | #endif | ||
1437 | argv++; | ||
1438 | } | ||
1418 | if (argv_expanded) { | 1439 | if (argv_expanded) { |
1419 | argv = argv_expanded; | 1440 | argv = argv_expanded; |
1420 | } else { | 1441 | } else { |
1421 | argv = expand_strvec_to_strvec(argv); | 1442 | argv = expand_strvec_to_strvec(argv); |
1422 | #if !BB_MMU | 1443 | #if !BB_MMU |
1423 | *ptrs2free++ = (char*) argv; | 1444 | /* Inserting magic guard pointer to not unsetenv junk later */ |
1445 | *ptr_ptrs2free = add_malloced_string_to_strings(*ptr_ptrs2free, (char*)hush_version_str); | ||
1446 | *ptr_ptrs2free = add_malloced_string_to_strings(*ptr_ptrs2free, (char*)argv); | ||
1424 | #endif | 1447 | #endif |
1425 | } | 1448 | } |
1426 | 1449 | ||
@@ -1466,10 +1489,10 @@ static void pseudo_exec_argv(char **ptrs2free, char **argv, int assignment_cnt, | |||
1466 | 1489 | ||
1467 | /* Called after [v]fork() in run_pipe() | 1490 | /* Called after [v]fork() in run_pipe() |
1468 | */ | 1491 | */ |
1469 | static void pseudo_exec(char **ptrs2free, struct command *command, char **argv_expanded) | 1492 | static void pseudo_exec(char ***ptr_ptrs2free, struct command *command, char **argv_expanded) |
1470 | { | 1493 | { |
1471 | if (command->argv) | 1494 | if (command->argv) |
1472 | pseudo_exec_argv(ptrs2free, command->argv, command->assignment_cnt, argv_expanded); | 1495 | pseudo_exec_argv(ptr_ptrs2free, command->argv, command->assignment_cnt, argv_expanded); |
1473 | 1496 | ||
1474 | if (command->group) { | 1497 | if (command->group) { |
1475 | #if !BB_MMU | 1498 | #if !BB_MMU |
@@ -1745,6 +1768,7 @@ static int run_pipe(struct pipe *pi) | |||
1745 | int nextin; | 1768 | int nextin; |
1746 | int pipefds[2]; /* pipefds[0] is for reading */ | 1769 | int pipefds[2]; /* pipefds[0] is for reading */ |
1747 | struct command *command; | 1770 | struct command *command; |
1771 | char **ptrs2free = NULL; | ||
1748 | char **argv_expanded = NULL; | 1772 | char **argv_expanded = NULL; |
1749 | char **argv; | 1773 | char **argv; |
1750 | const struct built_in_command *x; | 1774 | const struct built_in_command *x; |
@@ -1796,7 +1820,7 @@ static int run_pipe(struct pipe *pi) | |||
1796 | for (i = 0; i < command->assignment_cnt; i++) { | 1820 | for (i = 0; i < command->assignment_cnt; i++) { |
1797 | p = expand_string_to_string(argv[i]); | 1821 | p = expand_string_to_string(argv[i]); |
1798 | putenv(p); | 1822 | putenv(p); |
1799 | //FIXME: do we leak p?! | 1823 | ptrs2free = add_malloced_string_to_strings(ptrs2free, p); |
1800 | } | 1824 | } |
1801 | 1825 | ||
1802 | /* Expand the rest into (possibly) many strings each */ | 1826 | /* Expand the rest into (possibly) many strings each */ |
@@ -1805,9 +1829,10 @@ static int run_pipe(struct pipe *pi) | |||
1805 | for (x = bltins; x != &bltins[ARRAY_SIZE(bltins)]; x++) { | 1829 | for (x = bltins; x != &bltins[ARRAY_SIZE(bltins)]; x++) { |
1806 | if (strcmp(argv_expanded[0], x->cmd) == 0) { | 1830 | if (strcmp(argv_expanded[0], x->cmd) == 0) { |
1807 | if (x->function == builtin_exec && argv_expanded[1] == NULL) { | 1831 | if (x->function == builtin_exec && argv_expanded[1] == NULL) { |
1808 | debug_printf("magic exec\n"); | 1832 | debug_printf("exec with redirects only\n"); |
1809 | setup_redirects(command, NULL); | 1833 | setup_redirects(command, NULL); |
1810 | return EXIT_SUCCESS; | 1834 | rcode = EXIT_SUCCESS; |
1835 | goto clean_up_and_ret1; | ||
1811 | } | 1836 | } |
1812 | debug_printf("builtin inline %s\n", argv_expanded[0]); | 1837 | debug_printf("builtin inline %s\n", argv_expanded[0]); |
1813 | /* XXX setup_redirects acts on file descriptors, not FILEs. | 1838 | /* XXX setup_redirects acts on file descriptors, not FILEs. |
@@ -1817,10 +1842,13 @@ static int run_pipe(struct pipe *pi) | |||
1817 | setup_redirects(command, squirrel); | 1842 | setup_redirects(command, squirrel); |
1818 | debug_printf_exec(": builtin '%s' '%s'...\n", x->cmd, argv_expanded[1]); | 1843 | debug_printf_exec(": builtin '%s' '%s'...\n", x->cmd, argv_expanded[1]); |
1819 | rcode = x->function(argv_expanded) & 0xff; | 1844 | rcode = x->function(argv_expanded) & 0xff; |
1820 | free(argv_expanded); | 1845 | USE_FEATURE_SH_STANDALONE(clean_up_and_ret:) |
1821 | restore_redirects(squirrel); | 1846 | restore_redirects(squirrel); |
1822 | debug_printf_exec("run_pipe return %d\n", rcode); | 1847 | clean_up_and_ret1: |
1848 | free_strings_and_unsetenv(ptrs2free, 1); | ||
1849 | free(argv_expanded); | ||
1823 | IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;) | 1850 | IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;) |
1851 | debug_printf_exec("run_pipe return %d\n", rcode); | ||
1824 | return rcode; | 1852 | return rcode; |
1825 | } | 1853 | } |
1826 | } | 1854 | } |
@@ -1832,11 +1860,7 @@ static int run_pipe(struct pipe *pi) | |||
1832 | save_nofork_data(&G.nofork_save); | 1860 | save_nofork_data(&G.nofork_save); |
1833 | debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", argv_expanded[0], argv_expanded[1]); | 1861 | debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", argv_expanded[0], argv_expanded[1]); |
1834 | rcode = run_nofork_applet_prime(&G.nofork_save, a, argv_expanded); | 1862 | rcode = run_nofork_applet_prime(&G.nofork_save, a, argv_expanded); |
1835 | free(argv_expanded); | 1863 | goto clean_up_and_ret; |
1836 | restore_redirects(squirrel); | ||
1837 | debug_printf_exec("run_pipe return %d\n", rcode); | ||
1838 | IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;) | ||
1839 | return rcode; | ||
1840 | } | 1864 | } |
1841 | } | 1865 | } |
1842 | #endif | 1866 | #endif |
@@ -1856,14 +1880,15 @@ static int run_pipe(struct pipe *pi) | |||
1856 | 1880 | ||
1857 | for (i = 0; i < pi->num_cmds; i++) { | 1881 | for (i = 0; i < pi->num_cmds; i++) { |
1858 | #if !BB_MMU | 1882 | #if !BB_MMU |
1859 | char **ptrs2free = NULL; | 1883 | /* Avoid confusion WHAT is volatile. Pointer is volatile, |
1884 | * not the stuff it points to. */ | ||
1885 | typedef char **ppchar_t; | ||
1886 | volatile ppchar_t shared_across_vfork; | ||
1860 | #endif | 1887 | #endif |
1888 | |||
1861 | command = &(pi->cmds[i]); | 1889 | command = &(pi->cmds[i]); |
1862 | if (command->argv) { | 1890 | if (command->argv) { |
1863 | debug_printf_exec(": pipe member '%s' '%s'...\n", command->argv[0], command->argv[1]); | 1891 | debug_printf_exec(": pipe member '%s' '%s'...\n", command->argv[0], command->argv[1]); |
1864 | #if !BB_MMU | ||
1865 | ptrs2free = alloc_ptrs(command->argv); | ||
1866 | #endif | ||
1867 | } else | 1892 | } else |
1868 | debug_printf_exec(": pipe member with no argv\n"); | 1893 | debug_printf_exec(": pipe member with no argv\n"); |
1869 | 1894 | ||
@@ -1873,6 +1898,9 @@ static int run_pipe(struct pipe *pi) | |||
1873 | if ((i + 1) < pi->num_cmds) | 1898 | if ((i + 1) < pi->num_cmds) |
1874 | xpipe(pipefds); | 1899 | xpipe(pipefds); |
1875 | 1900 | ||
1901 | #if !BB_MMU | ||
1902 | shared_across_vfork = ptrs2free; | ||
1903 | #endif | ||
1876 | command->pid = BB_MMU ? fork() : vfork(); | 1904 | command->pid = BB_MMU ? fork() : vfork(); |
1877 | if (!command->pid) { /* child */ | 1905 | if (!command->pid) { /* child */ |
1878 | if (ENABLE_HUSH_JOB) | 1906 | if (ENABLE_HUSH_JOB) |
@@ -1906,13 +1934,19 @@ static int run_pipe(struct pipe *pi) | |||
1906 | set_jobctrl_sighandler(SIG_DFL); | 1934 | set_jobctrl_sighandler(SIG_DFL); |
1907 | set_misc_sighandler(SIG_DFL); | 1935 | set_misc_sighandler(SIG_DFL); |
1908 | signal(SIGCHLD, SIG_DFL); | 1936 | signal(SIGCHLD, SIG_DFL); |
1909 | pseudo_exec(ptrs2free, command, argv_expanded); /* does not return */ | 1937 | /* comment how it sets env???? |
1938 | for single_and_fg, it's already set yes? */ | ||
1939 | pseudo_exec((char ***) &shared_across_vfork, command, argv_expanded); | ||
1940 | /* pseudo_exec() does not return */ | ||
1910 | } | 1941 | } |
1911 | free(argv_expanded); | 1942 | /* parent */ |
1912 | argv_expanded = NULL; | ||
1913 | #if !BB_MMU | 1943 | #if !BB_MMU |
1914 | free_strings(ptrs2free); | 1944 | ptrs2free = shared_across_vfork; |
1915 | #endif | 1945 | #endif |
1946 | free(argv_expanded); | ||
1947 | argv_expanded = NULL; | ||
1948 | free_strings_and_unsetenv(ptrs2free, 1); | ||
1949 | ptrs2free = NULL; | ||
1916 | if (command->pid < 0) { /* [v]fork failed */ | 1950 | if (command->pid < 0) { /* [v]fork failed */ |
1917 | /* Clearly indicate, was it fork or vfork */ | 1951 | /* Clearly indicate, was it fork or vfork */ |
1918 | bb_perror_msg(BB_MMU ? "fork" : "vfork"); | 1952 | bb_perror_msg(BB_MMU ? "fork" : "vfork"); |
@@ -4077,10 +4111,9 @@ static void setup_job_control(void) | |||
4077 | int hush_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 4111 | int hush_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
4078 | int hush_main(int argc, char **argv) | 4112 | int hush_main(int argc, char **argv) |
4079 | { | 4113 | { |
4080 | static const char version_str[] ALIGN1 = "HUSH_VERSION="HUSH_VER_STR; | ||
4081 | static const struct variable const_shell_ver = { | 4114 | static const struct variable const_shell_ver = { |
4082 | .next = NULL, | 4115 | .next = NULL, |
4083 | .varstr = (char*)version_str, | 4116 | .varstr = (char*)hush_version_str, |
4084 | .max_len = 1, /* 0 can provoke free(name) */ | 4117 | .max_len = 1, /* 0 can provoke free(name) */ |
4085 | .flg_export = 1, | 4118 | .flg_export = 1, |
4086 | .flg_read_only = 1, | 4119 | .flg_read_only = 1, |
@@ -4114,7 +4147,7 @@ int hush_main(int argc, char **argv) | |||
4114 | } | 4147 | } |
4115 | e++; | 4148 | e++; |
4116 | } | 4149 | } |
4117 | putenv((char *)version_str); /* reinstate HUSH_VERSION */ | 4150 | putenv((char *)hush_version_str); /* reinstate HUSH_VERSION */ |
4118 | 4151 | ||
4119 | #if ENABLE_FEATURE_EDITING | 4152 | #if ENABLE_FEATURE_EDITING |
4120 | G.line_input_state = new_line_input_t(FOR_SHELL); | 4153 | G.line_input_state = new_line_input_t(FOR_SHELL); |
@@ -4338,10 +4371,10 @@ static int builtin_exec(char **argv) | |||
4338 | return EXIT_SUCCESS; /* bash does this */ | 4371 | return EXIT_SUCCESS; /* bash does this */ |
4339 | { | 4372 | { |
4340 | #if !BB_MMU | 4373 | #if !BB_MMU |
4341 | char **ptrs2free = alloc_ptrs(argv); | 4374 | char **ptrs2free = NULL; |
4342 | #endif | 4375 | #endif |
4343 | // FIXME: if exec fails, bash does NOT exit! We do... | 4376 | // FIXME: if exec fails, bash does NOT exit! We do... |
4344 | pseudo_exec_argv(ptrs2free, argv + 1, 0, NULL); | 4377 | pseudo_exec_argv(&ptrs2free, argv + 1, 0, NULL); |
4345 | /* never returns */ | 4378 | /* never returns */ |
4346 | } | 4379 | } |
4347 | } | 4380 | } |
diff --git a/shell/hush_test/hush-vars/var_leaks.right b/shell/hush_test/hush-vars/var_leaks.right new file mode 100644 index 000000000..d86bac9de --- /dev/null +++ b/shell/hush_test/hush-vars/var_leaks.right | |||
@@ -0,0 +1 @@ | |||
OK | |||
diff --git a/shell/hush_test/hush-vars/var_leaks.tests b/shell/hush_test/hush-vars/var_leaks.tests new file mode 100755 index 000000000..27c8c6504 --- /dev/null +++ b/shell/hush_test/hush-vars/var_leaks.tests | |||
@@ -0,0 +1,14 @@ | |||
1 | # external program | ||
2 | a=b /bin/true | ||
3 | env | grep ^a= | ||
4 | |||
5 | # builtin | ||
6 | a=b true | ||
7 | env | grep ^a= | ||
8 | |||
9 | # exec with redirection only | ||
10 | # in bash, this leaks! | ||
11 | a=b exec 1>&1 | ||
12 | env | grep ^a= | ||
13 | |||
14 | echo OK | ||
diff --git a/shell/hush_test/hush-z_slow/leak_var.tests b/shell/hush_test/hush-z_slow/leak_var.tests index 388d6a734..b3e13e308 100755 --- a/shell/hush_test/hush-z_slow/leak_var.tests +++ b/shell/hush_test/hush-z_slow/leak_var.tests | |||
@@ -42,6 +42,53 @@ while test $i != X; do | |||
42 | done | 42 | done |
43 | end=`ps -o pid,vsz | grep "^ *$pid "` | 43 | end=`ps -o pid,vsz | grep "^ *$pid "` |
44 | 44 | ||
45 | # Warm up again (I do need it on my machine) | ||
46 | beg=`ps -o pid,vsz | grep "^ *$pid "` | ||
47 | i=1 | ||
48 | while test $i != X; do | ||
49 | unset t | ||
50 | t=111111111111111111111111111111111111111111111111111111111111111111111111 | ||
51 | export t | ||
52 | unset t | ||
53 | t=111111111111111111111111111111111111111111111111111111111111111111111111 | ||
54 | export t | ||
55 | unset t | ||
56 | t=111111111111111111111111111111111111111111111111111111111111111111111111 | ||
57 | export t | ||
58 | unset t | ||
59 | t=111111111111111111111111111111111111111111111111111111111111111111111111 | ||
60 | export t | ||
61 | unset t | ||
62 | t=111111111111111111111111111111111111111111111111111111111111111111111111 | ||
63 | export t | ||
64 | i=1$i | ||
65 | if test $i = 1111111111111111111111111111111111111111111111; then i=2; fi | ||
66 | if test $i = 1111111111111111111111111111111111111111111112; then i=3; fi | ||
67 | if test $i = 1111111111111111111111111111111111111111111113; then i=4; fi | ||
68 | if test $i = 1111111111111111111111111111111111111111111114; then i=5; fi | ||
69 | if test $i = 1111111111111111111111111111111111111111111115; then i=6; fi | ||
70 | if test $i = 1111111111111111111111111111111111111111111116; then i=7; fi | ||
71 | if test $i = 1111111111111111111111111111111111111111111117; then i=8; fi | ||
72 | if test $i = 1111111111111111111111111111111111111111111118; then i=9; fi | ||
73 | if test $i = 1111111111111111111111111111111111111111111119; then i=a; fi | ||
74 | if test $i = 111111111111111111111111111111111111111111111a; then i=b; fi | ||
75 | if test $i = 111111111111111111111111111111111111111111111b; then i=c; fi | ||
76 | if test $i = 111111111111111111111111111111111111111111111c; then i=d; fi | ||
77 | if test $i = 111111111111111111111111111111111111111111111d; then i=e; fi | ||
78 | if test $i = 111111111111111111111111111111111111111111111e; then i=f; fi | ||
79 | if test $i = 111111111111111111111111111111111111111111111f; then i=g; fi | ||
80 | if test $i = 111111111111111111111111111111111111111111111g; then i=h; fi | ||
81 | if test $i = 111111111111111111111111111111111111111111111h; then i=i; fi | ||
82 | if test $i = 111111111111111111111111111111111111111111111i; then i=j; fi | ||
83 | if test $i = 111111111111111111111111111111111111111111111j; then i=X; fi | ||
84 | done | ||
85 | end=`ps -o pid,vsz | grep "^ *$pid "` | ||
86 | if test "$beg" != "$end"; then | ||
87 | true echo "vsz grows: $beg -> $end" | ||
88 | else | ||
89 | true echo "vsz does not grow" | ||
90 | fi | ||
91 | |||
45 | echo "Measuring memory leak..." | 92 | echo "Measuring memory leak..." |
46 | beg=`ps -o pid,vsz | grep "^ *$pid "` | 93 | beg=`ps -o pid,vsz | grep "^ *$pid "` |
47 | i=1 | 94 | i=1 |
diff --git a/shell/hush_test/hush-z_slow/leak_var2.right b/shell/hush_test/hush-z_slow/leak_var2.right new file mode 100644 index 000000000..7bccc1eef --- /dev/null +++ b/shell/hush_test/hush-z_slow/leak_var2.right | |||
@@ -0,0 +1,2 @@ | |||
1 | Measuring memory leak... | ||
2 | vsz does not grow | ||
diff --git a/shell/hush_test/hush-z_slow/leak_var2.tests b/shell/hush_test/hush-z_slow/leak_var2.tests new file mode 100755 index 000000000..09f247552 --- /dev/null +++ b/shell/hush_test/hush-z_slow/leak_var2.tests | |||
@@ -0,0 +1,63 @@ | |||
1 | pid=$$ | ||
2 | |||
3 | t=1 | ||
4 | export t | ||
5 | |||
6 | # Warm up | ||
7 | beg=`ps -o pid,vsz | grep "^ *$pid "` | ||
8 | i=1 | ||
9 | while test $i != X; do | ||
10 | t=111111111111111111111111111111111111111111111111111111111111111111111110$i | ||
11 | t=111111111111111111111111111111111111111111111111111111111111111111111111$i true | ||
12 | t=111111111111111111111111111111111111111111111111111111111111111111111112$i /bin/true | ||
13 | t=111111111111111111111111111111111111111111111111111111111111111111111113$i exec 1>&1 | ||
14 | i=1$i | ||
15 | if test $i = 1111111111111111111111111111111111111111111111; then i=2; fi | ||
16 | if test $i = 1111111111111111111111111111111111111111111112; then i=3; fi | ||
17 | if test $i = 1111111111111111111111111111111111111111111113; then i=4; fi | ||
18 | if test $i = 1111111111111111111111111111111111111111111114; then i=X; fi | ||
19 | done | ||
20 | end=`ps -o pid,vsz | grep "^ *$pid "` | ||
21 | |||
22 | # Warm up again (I do need it on my machine) | ||
23 | beg=`ps -o pid,vsz | grep "^ *$pid "` | ||
24 | i=1 | ||
25 | while test $i != X; do | ||
26 | t=111111111111111111111111111111111111111111111111111111111111111111111110$i | ||
27 | t=111111111111111111111111111111111111111111111111111111111111111111111111$i true | ||
28 | t=111111111111111111111111111111111111111111111111111111111111111111111112$i /bin/true | ||
29 | t=111111111111111111111111111111111111111111111111111111111111111111111113$i exec 1>&1 | ||
30 | i=1$i | ||
31 | if test $i = 1111111111111111111111111111111111111111111111; then i=2; fi | ||
32 | if test $i = 1111111111111111111111111111111111111111111112; then i=3; fi | ||
33 | if test $i = 1111111111111111111111111111111111111111111113; then i=4; fi | ||
34 | if test $i = 1111111111111111111111111111111111111111111114; then i=X; fi | ||
35 | done | ||
36 | end=`ps -o pid,vsz | grep "^ *$pid "` | ||
37 | if test "$beg" != "$end"; then | ||
38 | true echo "vsz grows: $beg -> $end" | ||
39 | else | ||
40 | true echo "vsz does not grow" | ||
41 | fi | ||
42 | |||
43 | echo "Measuring memory leak..." | ||
44 | beg=`ps -o pid,vsz | grep "^ *$pid "` | ||
45 | i=1 | ||
46 | while test $i != X; do | ||
47 | t=111111111111111111111111111111111111111111111111111111111111111111111110$i | ||
48 | t=111111111111111111111111111111111111111111111111111111111111111111111111$i true | ||
49 | t=111111111111111111111111111111111111111111111111111111111111111111111112$i /bin/true | ||
50 | t=111111111111111111111111111111111111111111111111111111111111111111111113$i exec 1>&1 | ||
51 | i=1$i | ||
52 | if test $i = 1111111111111111111111111111111111111111111111; then i=2; fi | ||
53 | if test $i = 1111111111111111111111111111111111111111111112; then i=3; fi | ||
54 | if test $i = 1111111111111111111111111111111111111111111113; then i=4; fi | ||
55 | if test $i = 1111111111111111111111111111111111111111111114; then i=X; fi | ||
56 | done | ||
57 | end=`ps -o pid,vsz | grep "^ *$pid "` | ||
58 | |||
59 | if test "$beg" != "$end"; then | ||
60 | echo "vsz grows: $beg -> $end" | ||
61 | else | ||
62 | echo "vsz does not grow" | ||
63 | fi | ||