diff --git a/NEWS b/NEWS index a501ec4fe..b52cc56d3 100644 --- a/NEWS +++ b/NEWS @@ -22,6 +22,10 @@ Any uppercase BUG_* names are modernish shell bug IDs. - In emacs mode, Insert escapes the next character. - In vi mode, Insert will switch the editor to insert mode (like in vim). +- Fixed a bug in SIGINT handling: if a script ran an external command that + interrupted itself (and only itself, not the process group) with SIGINT, + the script that ran the command was also interrupted. + 2022-01-28: - Fixed longstanding job control breakage that occurred on the interactive diff --git a/src/cmd/ksh93/sh/fault.c b/src/cmd/ksh93/sh/fault.c index 58183c4df..f6b80a94b 100644 --- a/src/cmd/ksh93/sh/fault.c +++ b/src/cmd/ksh93/sh/fault.c @@ -113,8 +113,6 @@ void sh_fault(register int sig) flag = sh.sigflag[sig]&~SH_SIGOFF; if(!trap) { - if(sig==SIGINT && (sh.trapnote&SH_SIGIGNORE)) - return; if(flag&SH_SIGIGNORE) { if(sh.subshell) @@ -386,7 +384,7 @@ void sh_chktrap(void) { register int sig=sh.st.trapmax; register char *trap; - if(!(sh.trapnote&~SH_SIGIGNORE)) + if(!sh.trapnote) sig=0; sh.trapnote &= ~SH_SIGTRAP; /* execute errexit trap first */ diff --git a/src/cmd/ksh93/sh/xec.c b/src/cmd/ksh93/sh/xec.c index cc7712728..d09a2f2eb 100644 --- a/src/cmd/ksh93/sh/xec.c +++ b/src/cmd/ksh93/sh/xec.c @@ -1650,7 +1650,7 @@ int sh_exec(register const Shnode_t *t, int flags) { if(!(sh.sigflag[SIGINT]&(SH_SIGFAULT|SH_SIGOFF))) sh_sigtrap(SIGINT); - sh.trapnote |= SH_SIGIGNORE; + sigblock(SIGINT); } if(sh.pipepid) sh.pipepid = parent; @@ -1665,11 +1665,7 @@ int sh_exec(register const Shnode_t *t, int flags) if(usepipe && tsetio && subdup && unpipe) sh_iounpipe(); if(!sh_isstate(SH_MONITOR)) - { - sh.trapnote &= ~SH_SIGIGNORE; - if(sh.exitval == (SH_EXITSIG|SIGINT)) - kill(sh.current_pid,SIGINT); - } + sigrelease(SIGINT); } if(type&FAMP) { diff --git a/src/cmd/ksh93/tests/signal.sh b/src/cmd/ksh93/tests/signal.sh index d02c2f7c8..87bcf276d 100755 --- a/src/cmd/ksh93/tests/signal.sh +++ b/src/cmd/ksh93/tests/signal.sh @@ -76,6 +76,8 @@ expect=01got_child23 [[ $actual == "$expect" ]] || err_exit 'SIGCHLD not working' \ "(expected $(printf %q "$expect"), got $(printf %q "$actual"))" +# ====== + # begin standalone SIGINT test generation cat > tst <<'!' @@ -243,14 +245,14 @@ chmod +x tst tst-? # end standalone test generation -export PATH=$PATH: +PATH=:$PATH typeset -A expected expected[---]="3-intr" expected[--d]="3-intr" expected[-t-]="3-intr 2-intr 1-intr 1-0258" expected[-td]="3-intr 2-intr 1-intr 1-0258" -expected[x--]="3-intr 2-intr 1-0000" -expected[x-d]="3-intr 2-intr 1-0000" +expected[x--]="3-intr 2-intr" +expected[x-d]="3-intr 2-intr" expected[xt-]="3-intr 2-intr 1-intr 1-0000" expected[xtd]="3-intr 2-intr 1-intr 1-0000" expected[z--]="3-intr 2-intr 1-0000" @@ -263,6 +265,10 @@ tst $SHELL > tst.got while read ops out do [[ $out == ${expected[$ops]} ]] || err_exit "interrupt $ops test failed -- expected '${expected[$ops]}', got '$out'" done < tst.got +unset expected +PATH=${PATH#:} + +# ====== if [[ ${SIG[USR1]} ]] then float s=$SECONDS @@ -553,5 +559,14 @@ got=$( set +x; { "$SHELL" bar; } 2>&1 ) (( (e=$?)==0 )) && [[ $got == "$exp" ]] || err_exit "segfaulting child process:" \ "(expected status 0 and $(printf %q "$exp"), got status $e and $(printf %q "$got"))" +# ====== +# A script that SIGINTs only itself (not the process group) should not cause the parent script to be interrupted +trap '' INT # workaround for old ksh -- ignore SIGINT or the entire test suite gets interrupted +exp='258, continuing' +got=$("$SHELL" -c 'trap + INT; "$SHELL" -c '\''kill -s INT $$'\''; echo "$?, continuing"') +((!(e = $?))) && [[ $got == "$exp" ]] || err_exit "child process interrupting itself interrupts parent" \ + "(got status $e$( ((e>128)) && print -n /SIG && kill -l "$e"), $(printf %q "$got"))" +trap - INT + # ====== exit $((Errors<125?Errors:125))