[git commit] ash, hush: add comment about masked SIGCHLD, handle SIG_IGNed SIGHUP as in bash

Denys Vlasenko vda.linux at googlemail.com
Tue Feb 18 15:46:01 UTC 2020


commit: https://git.busybox.net/busybox/commit/?id=23bc562a0556d1c0ddad4252fa8d46c863b5fa88
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/master

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 shell/ash.c  | 26 ++++++++++++++++++++------
 shell/hush.c | 20 +++++++++++++++++---
 2 files changed, 37 insertions(+), 9 deletions(-)

diff --git a/shell/ash.c b/shell/ash.c
index ff594050c..fea4b10a7 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -4307,8 +4307,19 @@ wait_block_or_sig(int *status)
 #if 1
 		sigfillset(&mask);
 		sigprocmask2(SIG_SETMASK, &mask); /* mask is updated */
-		while (!got_sigchld && !pending_sig)
+		while (!got_sigchld && !pending_sig) {
 			sigsuspend(&mask);
+			/* ^^^ add "sigdelset(&mask, SIGCHLD);" before sigsuspend
+			 * to make sure SIGCHLD is not masked off?
+			 * It was reported that this:
+			 *	fn() { : | return; }
+			 *	shopt -s lastpipe
+			 *	fn
+			 *	exec ash SCRIPT
+			 * under bash 4.4.23 runs SCRIPT with SIGCHLD masked,
+			 * making "wait" commands in SCRIPT block forever.
+			 */
+		}
 		sigprocmask(SIG_SETMASK, &mask, NULL);
 #else /* unsafe: a signal can set pending_sig after check, but before pause() */
 		while (!got_sigchld && !pending_sig)
@@ -14170,11 +14181,6 @@ init(void)
 	sigmode[SIGCHLD - 1] = S_DFL; /* ensure we install handler even if it is SIG_IGNed */
 	setsignal(SIGCHLD);
 
-	/* bash re-enables SIGHUP which is SIG_IGNed on entry.
-	 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
-	 */
-	signal(SIGHUP, SIG_DFL);
-
 	{
 		char **envp;
 		const char *p;
@@ -14512,6 +14518,14 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
 		}
 #endif
  state4: /* XXX ??? - why isn't this before the "if" statement */
+
+		/* Interactive bash re-enables SIGHUP which is SIG_IGNed on entry.
+		 * Try:
+		 * trap '' hup; bash; echo RET	# type "kill -hup $$", see SIGHUP having effect
+		 * trap '' hup; bash -c 'kill -hup $$; echo ALIVE'  # here SIGHUP is SIG_IGNed
+		 */
+		signal(SIGHUP, SIG_DFL);
+
 		cmdloop(1);
 	}
 #if PROFILE
diff --git a/shell/hush.c b/shell/hush.c
index 6e44d4e11..bced388bf 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -9775,10 +9775,14 @@ static void install_sighandlers(unsigned mask)
 		 */
 		if (sig == SIGCHLD)
 			continue;
-		/* bash re-enables SIGHUP which is SIG_IGNed on entry.
-		 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
+		/* Interactive bash re-enables SIGHUP which is SIG_IGNed on entry.
+		 * Try:
+		 * trap '' hup; bash; echo RET  # type "kill -hup $$", see SIGHUP having effect
+		 * trap '' hup; bash -c 'kill -hup $$; echo ALIVE'  # here SIGHUP is SIG_IGNed
 		 */
-		//if (sig == SIGHUP) continue; - TODO?
+		if (sig == SIGHUP && G_interactive_fd)
+			continue;
+		/* Unless one of the above signals, is it SIG_IGN? */
 		if (old_handler == SIG_IGN) {
 			/* oops... restore back to IGN, and record this fact */
 			install_sighandler(sig, old_handler);
@@ -11554,6 +11558,16 @@ static int wait_for_child_or_signal(struct pipe *waitfor_pipe, pid_t waitfor_pid
 		/* It is vitally important for sigsuspend that SIGCHLD has non-DFL handler! */
 		/* Note: sigsuspend invokes signal handler */
 		sigsuspend(&oldset);
+		/* ^^^ add "sigdelset(&oldset, SIGCHLD)" before sigsuspend
+		 * to make sure SIGCHLD is not masked off?
+		 * It was reported that this:
+		 *	fn() { : | return; }
+		 *	shopt -s lastpipe
+		 *	fn
+		 *	exec hush SCRIPT
+		 * under bash 4.4.23 runs SCRIPT with SIGCHLD masked,
+		 * making "wait" commands in SCRIPT block forever.
+		 */
  restore:
 		sigprocmask(SIG_SETMASK, &oldset, NULL);
  check_sig:


More information about the busybox-cvs mailing list