121ecfd234
* Small bugfix release - Add zsh-pipefix.patch to import pipe fixes from zsh.git - Remove upstream patches * zsh-osc-suseversion.patch * zsh-zypper-completion.patch OBS-URL: https://build.opensuse.org/package/show/shells/zsh?expand=0&rev=123
160 lines
4.9 KiB
Diff
160 lines
4.9 KiB
Diff
diff --git a/Src/exec.c b/Src/exec.c
|
|
index dccdc2b..4480033 100644
|
|
--- a/Src/exec.c
|
|
+++ b/Src/exec.c
|
|
@@ -1691,6 +1691,7 @@ execpline2(Estate state, wordcode pcode,
|
|
execcmd(state, input, output, how, last1 ? 1 : 2);
|
|
else {
|
|
int old_list_pipe = list_pipe;
|
|
+ int subsh_close = -1;
|
|
Wordcode next = state->pc + (*state->pc), pc;
|
|
wordcode code;
|
|
|
|
@@ -1738,6 +1739,7 @@ execpline2(Estate state, wordcode pcode,
|
|
} else {
|
|
/* otherwise just do the pipeline normally. */
|
|
addfilelist(NULL, pipes[0]);
|
|
+ subsh_close = pipes[0];
|
|
execcmd(state, input, pipes[1], how, 0);
|
|
}
|
|
zclose(pipes[1]);
|
|
@@ -1750,6 +1752,8 @@ execpline2(Estate state, wordcode pcode,
|
|
execpline2(state, *state->pc++, how, pipes[0], output, last1);
|
|
list_pipe = old_list_pipe;
|
|
cmdpop();
|
|
+ if (subsh_close != pipes[0])
|
|
+ zclose(pipes[0]);
|
|
}
|
|
}
|
|
|
|
diff --git a/Test/A05execution.ztst b/Test/A05execution.ztst
|
|
index c8320a1..61d24fe 100644
|
|
--- a/Test/A05execution.ztst
|
|
+++ b/Test/A05execution.ztst
|
|
@@ -202,3 +202,15 @@ F:the bug is still there or it reappeared. See workers-29973 for details.
|
|
0:Check $pipestatus with a known difficult case
|
|
>1 0 1 0 0
|
|
F:This similar test was triggering a reproducible failure with pipestatus.
|
|
+
|
|
+ { unsetopt MONITOR } 2>/dev/null
|
|
+ coproc { read -Et 5 || kill -INT $$ }
|
|
+ print -u $ZTST_fd 'This test takes 5 seconds to fail...'
|
|
+ { printf "%d\n" {1..20000} } | ( read -E )
|
|
+ print -p done
|
|
+ read -Ep
|
|
+0:Bug regression: piping a shell construct to an external process may hang
|
|
+>1
|
|
+>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
|
|
diff --git a/Src/exec.c b/Src/exec.c
|
|
index 4480033..f16cfd3 100644
|
|
--- a/Src/exec.c
|
|
+++ b/Src/exec.c
|
|
@@ -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.");
|
|
diff --git a/Src/jobs.c b/Src/jobs.c
|
|
index 371b8eb..a321172 100644
|
|
--- a/Src/jobs.c
|
|
+++ b/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) &&
|
|
diff --git a/Test/A05execution.ztst b/Test/A05execution.ztst
|
|
index 61d24fe..6abfd8b 100644
|
|
--- a/Test/A05execution.ztst
|
|
+++ b/Test/A05execution.ztst
|
|
@@ -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
|