aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2008-10-09 16:29:44 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2008-10-09 16:29:44 +0000
commitafd7a8d744b29daaedbba1969307bd9ce17e7dc3 (patch)
tree015fa25e84f72a32b31724add0969f51a03bb74d
parent07e05c100fe6ac2bc5aa3505daabb55224c06a1f (diff)
downloadbusybox-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.c149
-rw-r--r--shell/hush_test/hush-vars/var_leaks.right1
-rwxr-xr-xshell/hush_test/hush-vars/var_leaks.tests14
-rwxr-xr-xshell/hush_test/hush-z_slow/leak_var.tests47
-rw-r--r--shell/hush_test/hush-z_slow/leak_var2.right2
-rwxr-xr-xshell/hush_test/hush-z_slow/leak_var2.tests63
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);
525static int setup_redirects(struct command *prog, int squirrel[]); 525static int setup_redirects(struct command *prog, int squirrel[]);
526static int run_list(struct pipe *pi); 526static 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
533static void pseudo_exec_argv(char **ptrs2free, char **argv, int assignment_cnt, char **argv_expanded) NORETURN; 533static void pseudo_exec_argv(char ***ptr_ptrs2free, char **argv, int assignment_cnt, char **argv_expanded) NORETURN;
534static void pseudo_exec(char **ptrs2free, struct command *command, char **argv_expanded) NORETURN; 534static void pseudo_exec(char ***ptr_ptrs2free, struct command *command, char **argv_expanded) NORETURN;
535static int run_pipe(struct pipe *pi); 535static int run_pipe(struct pipe *pi);
536/* data structure manipulation: */ 536/* data structure manipulation: */
537static int setup_redirect(struct parse_context *ctx, int fd, redir_type style, struct in_str *input); 537static 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);
576static void unset_local_var(const char *name); 576static void unset_local_var(const char *name);
577 577
578 578
579static const char hush_version_str[] ALIGN1 = "HUSH_VERSION="HUSH_VER_STR;
580
581
579static int glob_needed(const char *s) 582static 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
653static void free_strings(char **strings) 656static 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 690static void free_strings(char **strings)
664#define EXTRA_PTRS 5 /* 1 for NULL, 1 for args, 3 for paranoid reasons */
665static 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) */
1396static void pseudo_exec_argv(char **ptrs2free, char **argv, int assignment_cnt, char **argv_expanded) 1417static 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 */
1469static void pseudo_exec(char **ptrs2free, struct command *command, char **argv_expanded) 1492static 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????
1938for 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)
4077int hush_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 4111int hush_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
4078int hush_main(int argc, char **argv) 4112int 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
2a=b /bin/true
3env | grep ^a=
4
5# builtin
6a=b true
7env | grep ^a=
8
9# exec with redirection only
10# in bash, this leaks!
11a=b exec 1>&1
12env | grep ^a=
13
14echo 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
42done 42done
43end=`ps -o pid,vsz | grep "^ *$pid "` 43end=`ps -o pid,vsz | grep "^ *$pid "`
44 44
45# Warm up again (I do need it on my machine)
46beg=`ps -o pid,vsz | grep "^ *$pid "`
47i=1
48while 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
84done
85end=`ps -o pid,vsz | grep "^ *$pid "`
86if test "$beg" != "$end"; then
87 true echo "vsz grows: $beg -> $end"
88else
89 true echo "vsz does not grow"
90fi
91
45echo "Measuring memory leak..." 92echo "Measuring memory leak..."
46beg=`ps -o pid,vsz | grep "^ *$pid "` 93beg=`ps -o pid,vsz | grep "^ *$pid "`
47i=1 94i=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 @@
1Measuring memory leak...
2vsz 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 @@
1pid=$$
2
3t=1
4export t
5
6# Warm up
7beg=`ps -o pid,vsz | grep "^ *$pid "`
8i=1
9while 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
19done
20end=`ps -o pid,vsz | grep "^ *$pid "`
21
22# Warm up again (I do need it on my machine)
23beg=`ps -o pid,vsz | grep "^ *$pid "`
24i=1
25while 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
35done
36end=`ps -o pid,vsz | grep "^ *$pid "`
37if test "$beg" != "$end"; then
38 true echo "vsz grows: $beg -> $end"
39else
40 true echo "vsz does not grow"
41fi
42
43echo "Measuring memory leak..."
44beg=`ps -o pid,vsz | grep "^ *$pid "`
45i=1
46while 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
56done
57end=`ps -o pid,vsz | grep "^ *$pid "`
58
59if test "$beg" != "$end"; then
60 echo "vsz grows: $beg -> $end"
61else
62 echo "vsz does not grow"
63fi