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

Re: subtle `echo' bug



On Jun 15,  2:56pm, Peter Stephenson wrote:
}
} This is rather garbled: the error message shown was a write error which
} you certainly wouldn't see if the process that failed to write received
} a SIGPIPE.

SIGPIPE is one of those signals that causes a process to exit if it is
not trapped, and zsh does not trap it.  So there's no opportunity for
the error message to be printed.

} Experimentation suggests a SIGPIPE to a subprocess in a pipeline in
} other shells doesn't cause the shell to abort execution.  I'm not sure
} where the logic in zsh is that's causing this.

Since SIGPIPE is causing the child process to exit, it's the SIGCHLD
handler in the parent that's at issue.  Ultimately I believe it's this
code in update_job():

		/* If we have `foo|while true; (( x++ )); done', and hit
		 * ^C, we have to stop the loop, too. */
		if ((val & 0200) && inforeground == 1) {
		    if (!errbrk_saved) {
			errbrk_saved = 1;
			prev_breaks = breaks;
			prev_errflag = errflag;
		    }
		    breaks = loops;
		    errflag = 1;
		    inerrflush();
		}

I've verified that (val & 0200) == 128 in this instance, which is not
distinguishable from the child having received a SIGINT.

Related may be this comment in zwaitjob():

	    /* Commenting this out makes ^C-ing a job started by a function
	       stop the whole function again.  But I guess it will stop
	       something else from working properly, we have to find out
	       what this might be.  --oberon

	    errflag = 0; */

(Golly, I'd completely forgotten about Oberon.  That comment goes back a
decade at least.)

So, we could try this patch:

Index: Src/jobs.c
===================================================================
RCS file: /extra/cvsroot/zsh/zsh-4.0/Src/jobs.c,v
retrieving revision 1.15
diff -c -r1.15 jobs.c
--- Src/jobs.c	26 Mar 2005 16:14:05 -0000	1.15
+++ Src/jobs.c	15 Jun 2005 15:26:07 -0000
@@ -383,7 +383,8 @@
 		}
 		/* If we have `foo|while true; (( x++ )); done', and hit
 		 * ^C, we have to stop the loop, too. */
-		if ((val & 0200) && inforeground == 1) {
+		if ((val & 0200) && inforeground == 1 &&
+		    (val - 128 != SIGPIPE)) {
 		    if (!errbrk_saved) {
 			errbrk_saved = 1;
 			prev_breaks = breaks;
@@ -399,7 +400,8 @@
 		adjustwinsize(0);
 	    }
 	}
-    } else if (list_pipe && (val & 0200) && inforeground == 1) {
+    } else if (list_pipe && (val & 0200) && inforeground == 1 &&
+	       (val - 128 != SIGPIPE)) {
 	if (!errbrk_saved) {
 	    errbrk_saved = 1;
 	    prev_breaks = breaks;



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