mirror of
git://git.code.sf.net/p/zsh/code
synced 2025-01-19 11:31:26 +01:00
32176: plug additional deadlock-inducing pipe descriptor leaks
This commit is contained in:
parent
634c03c76d
commit
aede5c52bf
4 changed files with 36 additions and 14 deletions
|
@ -1,3 +1,8 @@
|
|||
2013-12-21 Barton E. Schaefer <schaefer@brasslantern.com>
|
||||
|
||||
* PWS + Bart: 32176: plug additional descriptor leaks causing
|
||||
deadlock via different code paths; expand regression test
|
||||
|
||||
2013-12-21 Peter Stephenson <p.w.stephenson@ntlworld.com>
|
||||
|
||||
* Config/version.mk: update version to 5.0.4-dev-0 so as
|
||||
|
|
|
@ -2389,7 +2389,7 @@ static void
|
|||
execcmd(Estate state, int input, int output, int how, int last1)
|
||||
{
|
||||
HashNode hn = NULL;
|
||||
LinkList args;
|
||||
LinkList args, filelist = NULL;
|
||||
LinkNode node;
|
||||
Redir fn;
|
||||
struct multio *mfds[10];
|
||||
|
@ -2911,6 +2911,7 @@ execcmd(Estate state, int input, int output, int how, int last1)
|
|||
flags |= ESUB_KEEPTRAP;
|
||||
if (type == WC_SUBSH && !(how & Z_ASYNC))
|
||||
flags |= ESUB_JOB_CONTROL;
|
||||
filelist = jobtab[thisjob].filelist;
|
||||
entersubsh(flags);
|
||||
close(synch[1]);
|
||||
forked = 1;
|
||||
|
@ -3264,6 +3265,7 @@ execcmd(Estate state, int input, int output, int how, int last1)
|
|||
|
||||
if (is_shfunc) {
|
||||
/* It's a shell function */
|
||||
pipecleanfilelist(filelist);
|
||||
execshfunc((Shfunc) hn, args);
|
||||
} else {
|
||||
/* It's a builtin */
|
||||
|
@ -3342,6 +3344,7 @@ execcmd(Estate state, int input, int output, int how, int last1)
|
|||
DPUTS(varspc,
|
||||
"BUG: assignment before complex command");
|
||||
list_pipe = 0;
|
||||
pipecleanfilelist(filelist);
|
||||
/* If we're forked (and we should be), no need to return */
|
||||
DPUTS(last1 != 1 && !forked, "BUG: not exiting?");
|
||||
DPUTS(type != WC_SUBSH, "Not sure what we're doing.");
|
||||
|
|
38
Src/jobs.c
38
Src/jobs.c
|
@ -1173,6 +1173,30 @@ addfilelist(const char *name, int fd)
|
|||
zaddlinknode(ll, jf);
|
||||
}
|
||||
|
||||
/* Clean up pipes no longer needed associated with a job */
|
||||
|
||||
/**/
|
||||
void
|
||||
pipecleanfilelist(LinkList filelist)
|
||||
{
|
||||
LinkNode node;
|
||||
|
||||
if (!filelist)
|
||||
return;
|
||||
node = firstnode(filelist);
|
||||
while (node) {
|
||||
Jobfile jf = (Jobfile)getdata(node);
|
||||
if (jf->is_fd) {
|
||||
LinkNode next = nextnode(node);
|
||||
zclose(jf->u.fd);
|
||||
(void)remnode(filelist, node);
|
||||
zfree(jf, sizeof(*jf));
|
||||
node = next;
|
||||
} else
|
||||
incnode(node);
|
||||
}
|
||||
}
|
||||
|
||||
/* Finished with list of files for a job */
|
||||
|
||||
/**/
|
||||
|
@ -1415,19 +1439,7 @@ zwaitjob(int job, int wait_cmd)
|
|||
* we can't deadlock on the fact that those still exist, so
|
||||
* that's not a problem.
|
||||
*/
|
||||
LinkNode node = firstnode(jn->filelist);
|
||||
while (node) {
|
||||
Jobfile jf = (Jobfile)getdata(node);
|
||||
if (jf->is_fd) {
|
||||
LinkNode next = nextnode(node);
|
||||
(void)remnode(jn->filelist, node);
|
||||
zclose(jf->u.fd);
|
||||
zfree(jf, sizeof(*jf));
|
||||
node = next;
|
||||
} else {
|
||||
incnode(node);
|
||||
}
|
||||
}
|
||||
pipecleanfilelist(jn->filelist);
|
||||
}
|
||||
while (!errflag && jn->stat &&
|
||||
!(jn->stat & STAT_DONE) &&
|
||||
|
|
|
@ -207,10 +207,12 @@ F:This similar test was triggering a reproducible failure with pipestatus.
|
|||
coproc { read -Et 5 || kill -INT $$ }
|
||||
print -u $ZTST_fd 'This test takes 5 seconds to fail...'
|
||||
{ printf "%d\n" {1..20000} } | ( read -E )
|
||||
hang(){ printf "%d\n" {2..20000} | cat }; hang | ( read -E )
|
||||
print -p done
|
||||
read -Ep
|
||||
0:Bug regression: piping a shell construct to an external process may hang
|
||||
>1
|
||||
>2
|
||||
>done
|
||||
F:This test checks for a file descriptor leak that could cause the left
|
||||
F:side of a pipe to block on write after the right side has exited
|
||||
|
|
Loading…
Reference in a new issue