Fix a massive memory leak in the run_list_test() function.
Rename run_list_test() as free_pipe_list(). Rename run_pipe_test() as free_pipe(). -Erik
This commit is contained in:
parent
77d9268892
commit
bf7df04ec1
44
hush.c
44
hush.c
@ -357,8 +357,8 @@ static void mark_closed(int fd);
|
|||||||
static void close_all();
|
static void close_all();
|
||||||
/* "run" the final data structures: */
|
/* "run" the final data structures: */
|
||||||
static char *indenter(int i);
|
static char *indenter(int i);
|
||||||
static int run_list_test(struct pipe *head, int indent);
|
static int free_pipe_list(struct pipe *head, int indent);
|
||||||
static int run_pipe_test(struct pipe *pi, int indent);
|
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 pipe_wait(struct pipe *pi);
|
static int pipe_wait(struct pipe *pi);
|
||||||
@ -395,7 +395,6 @@ static int parse_file_outer(FILE *f);
|
|||||||
static void checkjobs();
|
static void checkjobs();
|
||||||
static void insert_bg_job(struct pipe *pi);
|
static void insert_bg_job(struct pipe *pi);
|
||||||
static void remove_bg_job(struct pipe *pi);
|
static void remove_bg_job(struct pipe *pi);
|
||||||
static void free_pipe(struct pipe *pi);
|
|
||||||
/* local variable support */
|
/* local variable support */
|
||||||
static char *get_local_var(const char *var);
|
static char *get_local_var(const char *var);
|
||||||
static void unset_local_var(const char *name);
|
static void unset_local_var(const char *name);
|
||||||
@ -1138,7 +1137,7 @@ static void pseudo_exec(struct child_prog *child)
|
|||||||
debug_printf("runtime nesting to group\n");
|
debug_printf("runtime nesting to group\n");
|
||||||
interactive=0; /* crucial!!!! */
|
interactive=0; /* crucial!!!! */
|
||||||
rcode = run_list_real(child->group);
|
rcode = run_list_real(child->group);
|
||||||
/* OK to leak memory by not calling run_list_test,
|
/* OK to leak memory by not calling free_pipe_list,
|
||||||
* since this process is about to exit */
|
* since this process is about to exit */
|
||||||
_exit(rcode);
|
_exit(rcode);
|
||||||
} else {
|
} else {
|
||||||
@ -1203,30 +1202,10 @@ static void remove_bg_job(struct pipe *pi)
|
|||||||
prev_pipe->next = pi->next;
|
prev_pipe->next = pi->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
free_pipe(pi);
|
free_pipe(pi, 0);
|
||||||
free(pi);
|
free(pi);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* free up all memory from a pipe */
|
|
||||||
static void free_pipe(struct pipe *pi)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < pi->num_progs; i++) {
|
|
||||||
free(pi->progs[i].argv);
|
|
||||||
if (pi->progs[i].redirects)
|
|
||||||
free(pi->progs[i].redirects);
|
|
||||||
}
|
|
||||||
if (pi->progs)
|
|
||||||
free(pi->progs);
|
|
||||||
if (pi->text)
|
|
||||||
free(pi->text);
|
|
||||||
if (pi->cmdbuf)
|
|
||||||
free(pi->cmdbuf);
|
|
||||||
memset(pi, 0, sizeof(struct pipe));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Checks to see if any background processes have exited -- if they
|
/* Checks to see if any background processes have exited -- if they
|
||||||
have, figure out why and see if a job has completed */
|
have, figure out why and see if a job has completed */
|
||||||
static void checkjobs()
|
static void checkjobs()
|
||||||
@ -1535,7 +1514,7 @@ static char *indenter(int i)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* return code is the exit status of the pipe */
|
/* return code is the exit status of the pipe */
|
||||||
static int run_pipe_test(struct pipe *pi, int indent)
|
static int free_pipe(struct pipe *pi, int indent)
|
||||||
{
|
{
|
||||||
char **p;
|
char **p;
|
||||||
struct child_prog *child;
|
struct child_prog *child;
|
||||||
@ -1554,7 +1533,7 @@ static int run_pipe_test(struct pipe *pi, int indent)
|
|||||||
child->argv=NULL;
|
child->argv=NULL;
|
||||||
} else if (child->group) {
|
} else if (child->group) {
|
||||||
final_printf("%s begin group (subshell:%d)\n",ind, child->subshell);
|
final_printf("%s begin group (subshell:%d)\n",ind, child->subshell);
|
||||||
ret_code = run_list_test(child->group,indent+3);
|
ret_code = free_pipe_list(child->group,indent+3);
|
||||||
final_printf("%s end group\n",ind);
|
final_printf("%s end group\n",ind);
|
||||||
} else {
|
} else {
|
||||||
final_printf("%s (nil)\n",ind);
|
final_printf("%s (nil)\n",ind);
|
||||||
@ -1577,15 +1556,14 @@ static int run_pipe_test(struct pipe *pi, int indent)
|
|||||||
return ret_code;
|
return ret_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int run_list_test(struct pipe *head, int indent)
|
static int free_pipe_list(struct pipe *head, int indent)
|
||||||
{
|
{
|
||||||
int rcode=0; /* if list has no members */
|
int rcode=0; /* if list has no members */
|
||||||
struct pipe *pi, *next;
|
struct pipe *pi, *next;
|
||||||
char *ind = indenter(indent);
|
char *ind = indenter(indent);
|
||||||
for (pi=head; pi; pi=next) {
|
for (pi=head; pi; pi=next) {
|
||||||
if (pi->num_progs == 0) break;
|
|
||||||
final_printf("%s pipe reserved mode %d\n", ind, pi->r_mode);
|
final_printf("%s pipe reserved mode %d\n", ind, pi->r_mode);
|
||||||
rcode = run_pipe_test(pi, indent);
|
rcode = free_pipe(pi, indent);
|
||||||
final_printf("%s pipe followup code %d\n", ind, pi->followup);
|
final_printf("%s pipe followup code %d\n", ind, pi->followup);
|
||||||
next=pi->next;
|
next=pi->next;
|
||||||
pi->next=NULL;
|
pi->next=NULL;
|
||||||
@ -1601,10 +1579,10 @@ static int run_list(struct pipe *pi)
|
|||||||
if (fake_mode==0) {
|
if (fake_mode==0) {
|
||||||
rcode = run_list_real(pi);
|
rcode = run_list_real(pi);
|
||||||
}
|
}
|
||||||
/* run_list_test has the side effect of clearing memory
|
/* free_pipe_list has the side effect of clearing memory
|
||||||
* In the long run that function can be merged with run_list_real,
|
* In the long run that function can be merged with run_list_real,
|
||||||
* but doing that now would hobble the debugging effort. */
|
* but doing that now would hobble the debugging effort. */
|
||||||
run_list_test(pi,0);
|
free_pipe_list(pi,0);
|
||||||
return rcode;
|
return rcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2142,7 +2120,7 @@ FILE *generate_stream_from_list(struct pipe *head)
|
|||||||
pf = fdopen(channel[0],"r");
|
pf = fdopen(channel[0],"r");
|
||||||
debug_printf("pipe on FILE *%p\n",pf);
|
debug_printf("pipe on FILE *%p\n",pf);
|
||||||
#else
|
#else
|
||||||
run_list_test(head,0);
|
free_pipe_list(head,0);
|
||||||
pf=popen("echo surrogate response","r");
|
pf=popen("echo surrogate response","r");
|
||||||
debug_printf("started fake pipe on FILE *%p\n",pf);
|
debug_printf("started fake pipe on FILE *%p\n",pf);
|
||||||
#endif
|
#endif
|
||||||
|
44
shell/hush.c
44
shell/hush.c
@ -357,8 +357,8 @@ static void mark_closed(int fd);
|
|||||||
static void close_all();
|
static void close_all();
|
||||||
/* "run" the final data structures: */
|
/* "run" the final data structures: */
|
||||||
static char *indenter(int i);
|
static char *indenter(int i);
|
||||||
static int run_list_test(struct pipe *head, int indent);
|
static int free_pipe_list(struct pipe *head, int indent);
|
||||||
static int run_pipe_test(struct pipe *pi, int indent);
|
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 pipe_wait(struct pipe *pi);
|
static int pipe_wait(struct pipe *pi);
|
||||||
@ -395,7 +395,6 @@ static int parse_file_outer(FILE *f);
|
|||||||
static void checkjobs();
|
static void checkjobs();
|
||||||
static void insert_bg_job(struct pipe *pi);
|
static void insert_bg_job(struct pipe *pi);
|
||||||
static void remove_bg_job(struct pipe *pi);
|
static void remove_bg_job(struct pipe *pi);
|
||||||
static void free_pipe(struct pipe *pi);
|
|
||||||
/* local variable support */
|
/* local variable support */
|
||||||
static char *get_local_var(const char *var);
|
static char *get_local_var(const char *var);
|
||||||
static void unset_local_var(const char *name);
|
static void unset_local_var(const char *name);
|
||||||
@ -1138,7 +1137,7 @@ static void pseudo_exec(struct child_prog *child)
|
|||||||
debug_printf("runtime nesting to group\n");
|
debug_printf("runtime nesting to group\n");
|
||||||
interactive=0; /* crucial!!!! */
|
interactive=0; /* crucial!!!! */
|
||||||
rcode = run_list_real(child->group);
|
rcode = run_list_real(child->group);
|
||||||
/* OK to leak memory by not calling run_list_test,
|
/* OK to leak memory by not calling free_pipe_list,
|
||||||
* since this process is about to exit */
|
* since this process is about to exit */
|
||||||
_exit(rcode);
|
_exit(rcode);
|
||||||
} else {
|
} else {
|
||||||
@ -1203,30 +1202,10 @@ static void remove_bg_job(struct pipe *pi)
|
|||||||
prev_pipe->next = pi->next;
|
prev_pipe->next = pi->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
free_pipe(pi);
|
free_pipe(pi, 0);
|
||||||
free(pi);
|
free(pi);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* free up all memory from a pipe */
|
|
||||||
static void free_pipe(struct pipe *pi)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < pi->num_progs; i++) {
|
|
||||||
free(pi->progs[i].argv);
|
|
||||||
if (pi->progs[i].redirects)
|
|
||||||
free(pi->progs[i].redirects);
|
|
||||||
}
|
|
||||||
if (pi->progs)
|
|
||||||
free(pi->progs);
|
|
||||||
if (pi->text)
|
|
||||||
free(pi->text);
|
|
||||||
if (pi->cmdbuf)
|
|
||||||
free(pi->cmdbuf);
|
|
||||||
memset(pi, 0, sizeof(struct pipe));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Checks to see if any background processes have exited -- if they
|
/* Checks to see if any background processes have exited -- if they
|
||||||
have, figure out why and see if a job has completed */
|
have, figure out why and see if a job has completed */
|
||||||
static void checkjobs()
|
static void checkjobs()
|
||||||
@ -1535,7 +1514,7 @@ static char *indenter(int i)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* return code is the exit status of the pipe */
|
/* return code is the exit status of the pipe */
|
||||||
static int run_pipe_test(struct pipe *pi, int indent)
|
static int free_pipe(struct pipe *pi, int indent)
|
||||||
{
|
{
|
||||||
char **p;
|
char **p;
|
||||||
struct child_prog *child;
|
struct child_prog *child;
|
||||||
@ -1554,7 +1533,7 @@ static int run_pipe_test(struct pipe *pi, int indent)
|
|||||||
child->argv=NULL;
|
child->argv=NULL;
|
||||||
} else if (child->group) {
|
} else if (child->group) {
|
||||||
final_printf("%s begin group (subshell:%d)\n",ind, child->subshell);
|
final_printf("%s begin group (subshell:%d)\n",ind, child->subshell);
|
||||||
ret_code = run_list_test(child->group,indent+3);
|
ret_code = free_pipe_list(child->group,indent+3);
|
||||||
final_printf("%s end group\n",ind);
|
final_printf("%s end group\n",ind);
|
||||||
} else {
|
} else {
|
||||||
final_printf("%s (nil)\n",ind);
|
final_printf("%s (nil)\n",ind);
|
||||||
@ -1577,15 +1556,14 @@ static int run_pipe_test(struct pipe *pi, int indent)
|
|||||||
return ret_code;
|
return ret_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int run_list_test(struct pipe *head, int indent)
|
static int free_pipe_list(struct pipe *head, int indent)
|
||||||
{
|
{
|
||||||
int rcode=0; /* if list has no members */
|
int rcode=0; /* if list has no members */
|
||||||
struct pipe *pi, *next;
|
struct pipe *pi, *next;
|
||||||
char *ind = indenter(indent);
|
char *ind = indenter(indent);
|
||||||
for (pi=head; pi; pi=next) {
|
for (pi=head; pi; pi=next) {
|
||||||
if (pi->num_progs == 0) break;
|
|
||||||
final_printf("%s pipe reserved mode %d\n", ind, pi->r_mode);
|
final_printf("%s pipe reserved mode %d\n", ind, pi->r_mode);
|
||||||
rcode = run_pipe_test(pi, indent);
|
rcode = free_pipe(pi, indent);
|
||||||
final_printf("%s pipe followup code %d\n", ind, pi->followup);
|
final_printf("%s pipe followup code %d\n", ind, pi->followup);
|
||||||
next=pi->next;
|
next=pi->next;
|
||||||
pi->next=NULL;
|
pi->next=NULL;
|
||||||
@ -1601,10 +1579,10 @@ static int run_list(struct pipe *pi)
|
|||||||
if (fake_mode==0) {
|
if (fake_mode==0) {
|
||||||
rcode = run_list_real(pi);
|
rcode = run_list_real(pi);
|
||||||
}
|
}
|
||||||
/* run_list_test has the side effect of clearing memory
|
/* free_pipe_list has the side effect of clearing memory
|
||||||
* In the long run that function can be merged with run_list_real,
|
* In the long run that function can be merged with run_list_real,
|
||||||
* but doing that now would hobble the debugging effort. */
|
* but doing that now would hobble the debugging effort. */
|
||||||
run_list_test(pi,0);
|
free_pipe_list(pi,0);
|
||||||
return rcode;
|
return rcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2142,7 +2120,7 @@ FILE *generate_stream_from_list(struct pipe *head)
|
|||||||
pf = fdopen(channel[0],"r");
|
pf = fdopen(channel[0],"r");
|
||||||
debug_printf("pipe on FILE *%p\n",pf);
|
debug_printf("pipe on FILE *%p\n",pf);
|
||||||
#else
|
#else
|
||||||
run_list_test(head,0);
|
free_pipe_list(head,0);
|
||||||
pf=popen("echo surrogate response","r");
|
pf=popen("echo surrogate response","r");
|
||||||
debug_printf("started fake pipe on FILE *%p\n",pf);
|
debug_printf("started fake pipe on FILE *%p\n",pf);
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user