diff --git a/NEWS b/NEWS index 7fb4f5573..6d4aa366f 100644 --- a/NEWS +++ b/NEWS @@ -20,6 +20,10 @@ Any uppercase BUG_* names are modernish shell bug IDs. - undocumented builtins 'vmap' and 'vpath' that only printed error messages - a non-functional -V unary operator for the test and [[ commands +- If the last program run by a ksh script exits with a signal (e.g. crashed), + ksh itself now exits normally instead of repeating that same signal. + In addition, using 'exit x' for x > 256 no longer makes ksh issue a signal. + 2020-06-06: - The 'times' command is now a builtin command that conforms to POSIX diff --git a/src/cmd/ksh93/bltins/cflow.c b/src/cmd/ksh93/bltins/cflow.c index d76f98532..fb2fccc6b 100644 --- a/src/cmd/ksh93/bltins/cflow.c +++ b/src/cmd/ksh93/bltins/cflow.c @@ -70,7 +70,7 @@ done: /* return outside of function, dotscript and profile is exit */ if(shp->fn_depth==0 && shp->dot_depth==0 && !sh_isstate(SH_PROFILE)) pp->mode = SH_JMPEXIT; - sh_exit(shp->savexit=n); + sh_exit((shp->savexit = n) & SH_EXITMASK); return(1); } diff --git a/src/cmd/ksh93/sh/fault.c b/src/cmd/ksh93/sh/fault.c index 8e8ee510c..30c536a7b 100644 --- a/src/cmd/ksh93/sh/fault.c +++ b/src/cmd/ksh93/sh/fault.c @@ -643,7 +643,7 @@ void sh_done(void *ptr, register int sig) sfsync((Sfio_t*)sfstdin); sfsync((Sfio_t*)shp->outpool); sfsync((Sfio_t*)sfstdout); - if(savxit&SH_EXITSIG) + if(savxit&SH_EXITSIG && (savxit&SH_EXITMASK) == shp->lastsig) sig = savxit&SH_EXITMASK; if(sig) { @@ -668,6 +668,11 @@ void sh_done(void *ptr, register int sig) if(sh_isoption(SH_NOEXEC)) kiaclose((Lex_t*)shp->lex_context); #endif /* SHOPT_KIA */ + + /* Exit with portable 8-bit status (128 + signum) if last child process exits due to signal */ + if (savxit & SH_EXITSIG) + savxit -= SH_EXITSIG + 128; + exit(savxit&SH_EXITMASK); } diff --git a/src/cmd/ksh93/tests/signal.sh b/src/cmd/ksh93/tests/signal.sh index 87cfd7d92..1e35b212c 100755 --- a/src/cmd/ksh93/tests/signal.sh +++ b/src/cmd/ksh93/tests/signal.sh @@ -437,4 +437,26 @@ a [[ $endb ]] && err_exit 'TERM signal did not kill function b' [[ $enda == 1 ]] || err_exit 'TERM signal killed function a' +# ====== +# Exit status checks + +# Verify that 'exit x' for x > 256 does not make the shell send a signal to itself +"$SHELL" -c 'exit $((256+9))' +let "$? == 256+9" && err_exit 'exit with status > 256 makes shell kill itself' + +# Verify that the shell does not kill itself after detecting that a child process is killed by a signal, +# and that a signal still causes the exit status to be set to a value > 128 +cat >"$tmp/sigtest.sh" <<\EOF +echo begin +sh -c 'kill -9 "$$"' +EOF +expect=$'^begin\n/.*/sigtest.sh: line 2: [1-9][0-9]*: Killed\n[1-9][0-9]{1,2}$' +actual=$("$SHELL" -c 'ksh "$1"; echo "$?"' x "$tmp/sigtest.sh" 2>&1) +if ! [[ $actual =~ $expect ]] +then [[ $actual == *Killed*Killed* ]] && msg='ksh killed itself' || msg='unexpected output' + err_exit "$msg after child process signal (expected match to $(printf %q "$expect"); got $(printf %q "$actual"))" +fi +let "${actual##*$'\n'} > 128" || err_exit "child process signal did not cause exit status > 128" + +# ====== exit $((Errors<125?Errors:125))