mirror of
https://github.com/sheumann/hush.git
synced 2025-01-16 09:30:29 +00:00
hush: fix a memory leak in NOMMU case
This commit is contained in:
parent
3fe4f986a0
commit
76d50418b3
56
shell/hush.c
56
shell/hush.c
@ -516,8 +516,12 @@ static int free_pipe(struct pipe *pi, int indent);
|
|||||||
/* really run the final data structures: */
|
/* really run the final data structures: */
|
||||||
static int setup_redirects(struct child_prog *prog, int squirrel[]);
|
static int setup_redirects(struct child_prog *prog, int squirrel[]);
|
||||||
static int run_list(struct pipe *pi);
|
static int run_list(struct pipe *pi);
|
||||||
static void pseudo_exec_argv(char **argv) ATTRIBUTE_NORETURN;
|
#if BB_MMU
|
||||||
static void pseudo_exec(struct child_prog *child) ATTRIBUTE_NORETURN;
|
#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);
|
static int run_pipe(struct pipe *pi);
|
||||||
/* extended glob support: */
|
/* extended glob support: */
|
||||||
static char **globhack(const char *src, char **strings);
|
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 */
|
/* Function prototypes for builtins */
|
||||||
static int builtin_cd(char **argv);
|
static int builtin_cd(char **argv);
|
||||||
static int builtin_echo(char **argv);
|
static int builtin_echo(char **argv);
|
||||||
@ -891,9 +907,14 @@ static int builtin_exec(char **argv)
|
|||||||
{
|
{
|
||||||
if (argv[1] == NULL)
|
if (argv[1] == NULL)
|
||||||
return EXIT_SUCCESS; /* bash does this */
|
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...
|
// FIXME: if exec fails, bash does NOT exit! We do...
|
||||||
pseudo_exec_argv(argv + 1);
|
pseudo_exec_argv(ptrs2free, argv + 1);
|
||||||
/* never returns */
|
/* never returns */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* built-in 'exit' handler */
|
/* 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.
|
* XXX no exit() here. If you don't exec, use _exit instead.
|
||||||
* The at_exit handlers apparently confuse the calling process,
|
* The at_exit handlers apparently confuse the calling process,
|
||||||
* in particular stdin handling. Not sure why? -- because of vfork! (vda) */
|
* 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;
|
int i, rcode;
|
||||||
char *p;
|
char *p;
|
||||||
@ -1430,8 +1451,10 @@ static void pseudo_exec_argv(char **argv)
|
|||||||
for (i = 0; is_assignment(argv[i]); i++) {
|
for (i = 0; is_assignment(argv[i]); i++) {
|
||||||
debug_printf_exec("pid %d environment modification: %s\n",
|
debug_printf_exec("pid %d environment modification: %s\n",
|
||||||
getpid(), argv[i]);
|
getpid(), argv[i]);
|
||||||
// FIXME: vfork case??
|
|
||||||
p = expand_string_to_string(argv[i]);
|
p = expand_string_to_string(argv[i]);
|
||||||
|
#if !BB_MMU
|
||||||
|
*ptrs2free++ = p;
|
||||||
|
#endif
|
||||||
putenv(p);
|
putenv(p);
|
||||||
}
|
}
|
||||||
argv += i;
|
argv += i;
|
||||||
@ -1442,6 +1465,9 @@ static void pseudo_exec_argv(char **argv)
|
|||||||
_exit(EXIT_SUCCESS);
|
_exit(EXIT_SUCCESS);
|
||||||
|
|
||||||
argv = expand_strvec_to_strvec(argv);
|
argv = expand_strvec_to_strvec(argv);
|
||||||
|
#if !BB_MMU
|
||||||
|
*ptrs2free++ = (char*) argv;
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check if the command matches any of the builtins.
|
* 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()
|
/* 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
|
// FIXME: buggy wrt NOMMU! Must not modify any global data
|
||||||
// until it does exec/_exit, but currently it does
|
// until it does exec/_exit, but currently it does
|
||||||
// (puts malloc'ed stuff into environment)
|
// (puts malloc'ed stuff into environment)
|
||||||
if (child->argv)
|
if (child->argv)
|
||||||
pseudo_exec_argv(child->argv);
|
pseudo_exec_argv(ptrs2free, child->argv);
|
||||||
|
|
||||||
if (child->group) {
|
if (child->group) {
|
||||||
#if !BB_MMU
|
#if !BB_MMU
|
||||||
@ -1880,10 +1906,16 @@ static int run_pipe(struct pipe *pi)
|
|||||||
nextin = 0;
|
nextin = 0;
|
||||||
|
|
||||||
for (i = 0; i < pi->num_progs; i++) {
|
for (i = 0; i < pi->num_progs; i++) {
|
||||||
|
#if !BB_MMU
|
||||||
|
char **ptrs2free = NULL;
|
||||||
|
#endif
|
||||||
child = &(pi->progs[i]);
|
child = &(pi->progs[i]);
|
||||||
if (child->argv)
|
if (child->argv) {
|
||||||
debug_printf_exec(": pipe member '%s' '%s'...\n", child->argv[0], child->argv[1]);
|
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");
|
debug_printf_exec(": pipe member with no argv\n");
|
||||||
|
|
||||||
/* pipes are inserted between pairs of commands */
|
/* pipes are inserted between pairs of commands */
|
||||||
@ -1925,9 +1957,11 @@ static int run_pipe(struct pipe *pi)
|
|||||||
set_jobctrl_sighandler(SIG_DFL);
|
set_jobctrl_sighandler(SIG_DFL);
|
||||||
set_misc_sighandler(SIG_DFL);
|
set_misc_sighandler(SIG_DFL);
|
||||||
signal(SIGCHLD, 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 */
|
if (child->pid < 0) { /* [v]fork failed */
|
||||||
/* Clearly indicate, was it fork or vfork */
|
/* Clearly indicate, was it fork or vfork */
|
||||||
bb_perror_msg(BB_MMU ? "fork" : "vfork");
|
bb_perror_msg(BB_MMU ? "fork" : "vfork");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user