Files
patches/zsh_patches/zsh-cmdsubst-hang.patch
2026-05-26 02:08:47 -05:00

64 lines
1.6 KiB
Diff

diff -u a/Src/exec.c b/Src/exec.c
--- a/Src/exec.c 2022-05-08 01:18:22.000000000 -0500
+++ b/Src/exec.c 2026-02-25 22:23:44.602848997 -0600
@@ -4679,7 +4679,34 @@
zclose(pipes[1]);
retval = readoutput(pipes[0], qt, NULL);
fdtable[pipes[0]] = FDT_UNUSED;
- waitforpid(pid, 0); /* unblocks */
+ wait_for_processes();
+ /*
+ * The SIGCHLD handler may already have reaped the command
+ * substitution child while readoutput() had signals unblocked.
+ * In that case cmdoutpid is cleared, and calling waitforpid()
+ * on a stale PID can hang if the PID has been reused.
+ */
+ if (cmdoutpid == pid) {
+ int status;
+ pid_t waitret;
+
+ while ((waitret = waitpid(pid, &status, 0)) < 0 && errno == EINTR)
+ ;
+ if (waitret == pid) {
+ cmdoutpid = 0;
+ if (WIFSIGNALED(status))
+ cmdoutval = (0200 | WTERMSIG(status));
+ else
+ cmdoutval = WEXITSTATUS(status);
+ use_cmdoutval = 1;
+ get_usage();
+ } else if (waitret < 0 && errno == ECHILD) {
+ wait_for_processes();
+ if (cmdoutpid == pid)
+ cmdoutpid = 0;
+ }
+ }
+ child_unblock();
lastval = cmdoutval;
return retval;
}
@@ -4884,7 +4911,22 @@
return nam;
} else if (pid) {
close(fd);
- waitforpid(pid, 0);
+ wait_for_processes();
+ if (cmdoutpid == pid) {
+ int status;
+ pid_t waitret;
+
+ while ((waitret = waitpid(pid, &status, 0)) < 0 && errno == EINTR)
+ ;
+ if (waitret == pid)
+ cmdoutpid = 0;
+ else if (waitret < 0 && errno == ECHILD) {
+ wait_for_processes();
+ if (cmdoutpid == pid)
+ cmdoutpid = 0;
+ }
+ }
+ child_unblock();
cmdoutval = 0;
return nam;
}