Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: [BUG] process substitution breaks when nested or traverses a function



On Sat, 21 Apr 2018 06:35:23 -0300
Francisco de Zuviría Allende <franciscodezuviria@xxxxxxxxx> wrote:
> #!/bin/zsh
> foo() { cat <(cat "$@"); }; foo <(echo bar);
> cat: /proc/self/fd/11: No such file or directory

Files and file descriptors for process substitution are handled
specially, so shouldn't be tidied up by closem(), which is called on the
inner process substitution (that's why both were required for this to
show up).

Is there a better way of doing this; or is this patch overkill, or not
careful enough...?  If we don't have /proc/self, tidying up is done only
with the job filelist, so there wouldn't be a problem.  But the get out
"all" argument looks like a reasonable safety compromise.

pws

diff --git a/Src/Modules/clone.c b/Src/Modules/clone.c
index 9304292..ef6275d 100644
--- a/Src/Modules/clone.c
+++ b/Src/Modules/clone.c
@@ -69,7 +69,7 @@ bin_clone(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
 	dup2(ttyfd,2);
 	if (ttyfd > 2)
 	    close(ttyfd);
-	closem(0);
+	closem(FDT_UNUSED, 0);
 	close(coprocin);
 	close(coprocout);
 	/* Acquire a controlling terminal */
diff --git a/Src/Modules/zpty.c b/Src/Modules/zpty.c
index 1c93a1d..2f83f7c 100644
--- a/Src/Modules/zpty.c
+++ b/Src/Modules/zpty.c
@@ -400,7 +400,7 @@ newptycmd(char *nam, char *pname, char **args, int echo, int nblock)
 	dup2(slave, 1);
 	dup2(slave, 2);
 
-	closem(0);
+	closem(FDT_UNUSED, 0);
 	close(slave);
 	close(master);
 	close(coprocin);
diff --git a/Src/exec.c b/Src/exec.c
index e853aff..65139de 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -698,7 +698,7 @@ execute(LinkList args, int flags, int defpath)
      * Note that we don't close fd's attached to process substitution
      * here, which should be visible to external processes.
      */
-    closem(FDT_XTRACE);
+    closem(FDT_XTRACE, 0);
 #ifndef FD_CLOEXEC
     if (SHTTY != -1) {
 	close(SHTTY);
@@ -3924,7 +3924,7 @@ execcmd_exec(Estate state, Execcmd_params eparams,
 		LinkList assigns = (LinkList)0;
 		int postassigns = eparams->postassigns;
 		if (forked)
-		    closem(FDT_INTERNAL);
+		    closem(FDT_INTERNAL, 0);
 		if (postassigns) {
 		    Wordcode opc = state->pc;
 		    state->pc = eparams->assignspc;
@@ -4110,7 +4110,7 @@ execcmd_exec(Estate state, Execcmd_params eparams,
 		    if (errflag)
 			_exit(1);
 		}
-		closem(FDT_INTERNAL);
+		closem(FDT_INTERNAL, 0);
 		if (coprocin != -1) {
 		    zclose(coprocin);
 		    coprocin = -1;
@@ -4172,7 +4172,7 @@ execcmd_exec(Estate state, Execcmd_params eparams,
 	for (i = 0; i < 10; i++)
 	    if (fdtable[i] != FDT_UNUSED)
 		close(i);
-	closem(FDT_UNUSED);
+	closem(FDT_UNUSED, 1);
 	if (thisjob != -1)
 	    waitjobs();
 	_exit(lastval);
@@ -4352,12 +4352,17 @@ fixfds(int *save)
 
 /**/
 mod_export void
-closem(int how)
+closem(int how, int all)
 {
     int i;
 
     for (i = 10; i <= max_zsh_fd; i++)
 	if (fdtable[i] != FDT_UNUSED &&
+	    /*
+	     * Process substitution needs to be visible to user;
+	     * fd's are explicitly cleaned up by filelist handling.
+	     */
+	    (all || fdtable[i] != FDT_PROC_SUBST) &&
 	    (how == FDT_UNUSED || (fdtable[i] & FDT_TYPE_MASK) == how)) {
 	    if (i == SHTTY)
 		SHTTY = -1;
@@ -4840,7 +4845,7 @@ getproc(char *cmd, char **eptr)
 	    addproc(pid, NULL, 1, &bgtime);
 	return pnam;
     }
-    closem(FDT_UNUSED);
+    closem(FDT_UNUSED, 0);
     fd = open(pnam, out ? O_WRONLY | O_NOCTTY : O_RDONLY | O_NOCTTY);
     if (fd == -1) {
 	zerr("can't open %s: %e", pnam, errno);
@@ -4879,7 +4884,7 @@ getproc(char *cmd, char **eptr)
     }
     entersubsh(ESUB_ASYNC|ESUB_PGRP);
     redup(pipes[out], out);
-    closem(FDT_UNUSED);   /* this closes pipes[!out] as well */
+    closem(FDT_UNUSED, 0);   /* this closes pipes[!out] as well */
 #endif /* PATH_DEV_FD */
 
     cmdpush(CS_CMDSUBST);
@@ -4929,7 +4934,7 @@ getpipe(char *cmd, int nullexec)
     }
     entersubsh(ESUB_PGRP);
     redup(pipes[out], out);
-    closem(FDT_UNUSED);	/* this closes pipes[!out] as well */
+    closem(FDT_UNUSED, 0);	/* this closes pipes[!out] as well */
     cmdpush(CS_CMDSUBST);
     execode(prog, 0, 1, out ? "outsubst" : "insubst");
     cmdpop();
diff --git a/Test/D03procsubst.ztst b/Test/D03procsubst.ztst
index ca8d56f..861aa9c 100644
--- a/Test/D03procsubst.ztst
+++ b/Test/D03procsubst.ztst
@@ -149,3 +149,10 @@
   fi
 0:proc subst fd in forked subshell closed in parent (external command)
 >1	1
+
+  procfunc() {
+    cat <(cat "$@")
+  }
+  procfunc <(echo argument)
+0:With /proc/self file descriptors must not be tidied up too early
+>argument



Messages sorted by: Reverse Date, Date, Thread, Author