From 76d50418b37e59c4b474137ffa2eba4d3f7dbbb8 Mon Sep 17 00:00:00 2001 From: Denis Vlasenko Date: Tue, 10 Jun 2008 16:19:39 +0000 Subject: hush: fix a memory leak in NOMMU case --- shell/hush.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 46 insertions(+), 12 deletions(-) (limited to 'shell/hush.c') diff --git a/shell/hush.c b/shell/hush.c index b80468f58..d7b9c39ec 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -516,8 +516,12 @@ static int free_pipe(struct pipe *pi, int indent); /* really run the final data structures: */ static int setup_redirects(struct child_prog *prog, int squirrel[]); static int run_list(struct pipe *pi); -static void pseudo_exec_argv(char **argv) ATTRIBUTE_NORETURN; -static void pseudo_exec(struct child_prog *child) ATTRIBUTE_NORETURN; +#if BB_MMU +#define pseudo_exec_argv(ptrs2free, argv) pseudo_exec_argv(argv) +#define pseudo_exec(ptrs2free, child) pseudo_exec(child) +#endif +static void pseudo_exec_argv(char **ptrs2free, char **argv) ATTRIBUTE_NORETURN; +static void pseudo_exec(char **ptrs2free, struct child_prog *child) ATTRIBUTE_NORETURN; static int run_pipe(struct pipe *pi); /* extended glob support: */ static char **globhack(const char *src, char **strings); @@ -619,6 +623,18 @@ static void free_strings(char **strings) } +#if !BB_MMU +#define EXTRA_PTRS 5 /* 1 for NULL, 1 for args, 3 for paranoid reasons */ +static char **alloc_ptrs(char **argv) +{ + char **v = argv; + while (*v) + v++; + return xzalloc((v - argv + EXTRA_PTRS) * sizeof(v[0])); +} +#endif + + /* Function prototypes for builtins */ static int builtin_cd(char **argv); static int builtin_echo(char **argv); @@ -891,9 +907,14 @@ static int builtin_exec(char **argv) { if (argv[1] == NULL) return EXIT_SUCCESS; /* bash does this */ + { +#if !BB_MMU + char **ptrs2free = alloc_ptrs(argv); +#endif // FIXME: if exec fails, bash does NOT exit! We do... - pseudo_exec_argv(argv + 1); - /* never returns */ + pseudo_exec_argv(ptrs2free, argv + 1); + /* never returns */ + } } /* built-in 'exit' handler */ @@ -1421,7 +1442,7 @@ static void restore_redirects(int squirrel[]) * XXX no exit() here. If you don't exec, use _exit instead. * The at_exit handlers apparently confuse the calling process, * in particular stdin handling. Not sure why? -- because of vfork! (vda) */ -static void pseudo_exec_argv(char **argv) +static void pseudo_exec_argv(char **ptrs2free, char **argv) { int i, rcode; char *p; @@ -1430,8 +1451,10 @@ static void pseudo_exec_argv(char **argv) for (i = 0; is_assignment(argv[i]); i++) { debug_printf_exec("pid %d environment modification: %s\n", getpid(), argv[i]); -// FIXME: vfork case?? p = expand_string_to_string(argv[i]); +#if !BB_MMU + *ptrs2free++ = p; +#endif putenv(p); } argv += i; @@ -1442,6 +1465,9 @@ static void pseudo_exec_argv(char **argv) _exit(EXIT_SUCCESS); argv = expand_strvec_to_strvec(argv); +#if !BB_MMU + *ptrs2free++ = (char*) argv; +#endif /* * Check if the command matches any of the builtins. @@ -1485,13 +1511,13 @@ static void pseudo_exec_argv(char **argv) /* Called after [v]fork() in run_pipe() */ -static void pseudo_exec(struct child_prog *child) +static void pseudo_exec(char **ptrs2free, struct child_prog *child) { // FIXME: buggy wrt NOMMU! Must not modify any global data // until it does exec/_exit, but currently it does // (puts malloc'ed stuff into environment) if (child->argv) - pseudo_exec_argv(child->argv); + pseudo_exec_argv(ptrs2free, child->argv); if (child->group) { #if !BB_MMU @@ -1880,10 +1906,16 @@ static int run_pipe(struct pipe *pi) nextin = 0; for (i = 0; i < pi->num_progs; i++) { +#if !BB_MMU + char **ptrs2free = NULL; +#endif child = &(pi->progs[i]); - if (child->argv) + if (child->argv) { debug_printf_exec(": pipe member '%s' '%s'...\n", child->argv[0], child->argv[1]); - else +#if !BB_MMU + ptrs2free = alloc_ptrs(child->argv); +#endif + } else debug_printf_exec(": pipe member with no argv\n"); /* pipes are inserted between pairs of commands */ @@ -1925,9 +1957,11 @@ static int run_pipe(struct pipe *pi) set_jobctrl_sighandler(SIG_DFL); set_misc_sighandler(SIG_DFL); signal(SIGCHLD, SIG_DFL); - pseudo_exec(child); /* does not return */ + pseudo_exec(ptrs2free, child); /* does not return */ } - +#if !BB_MMU + free_strings(ptrs2free); +#endif if (child->pid < 0) { /* [v]fork failed */ /* Clearly indicate, was it fork or vfork */ bb_perror_msg(BB_MMU ? "fork" : "vfork"); -- cgit v1.2.3