From 1026006db30f94c788b7de89ab69ddf7fc8b81fb Mon Sep 17 00:00:00 2001 From: Martijn Dekker Date: Thu, 4 Jun 2020 05:19:59 +0200 Subject: [PATCH] Fix BUG_KBGPID: $! was not updated under certain conditions The $! special parameter was not set if a background job (somecommand &) or co-process (somecommand |&) was launched as the only command within a braces block with an attached redirection, for example: { somecommand & } >&2 With the bug, $! was unchanged; now it contains the PID of somecommand. Ref.: https://github.com/att/ast/issues/1357 src/cmd/ksh93/sh/parse.c: item(): - When processing redirections following a compound command, always create a parent node with the TSETIO (I/O redirection) token. Before this commit, if the last command was of type TFORK (and the last command only tested as TFORK if the bg job or coprocess was the only command in a braces block, because the ksh parser optimises away the braces in that case), then the parent node was created with the TFORK token instead. I have no idea what David Korn's intention was with that, but this is clearly very wrong. Creating another TFORK node when parsing the redirection caused sh_exec() in sh/xec.c to execute the redirection in an extra forked, non-background subshell. Since redirections are executed before anything else, this subshell is what then launched the background job between the braces, so $! (a.k.a. shp->bckpid) was updated in that subshell only, and never in the main shell. The extra subshell also prevented the background job from being noticed by job control on interactive shells. So, the fix is simply to remove the broken test for TFORK. src/cmd/ksh93/tests/variables.sh: - Add regression tests for a bg job and a co-process as the only command within a braces block with attached redirection. (cherry picked from commit ffe5df30e69f7b596941a98498014d8e838861f2) --- NEWS | 10 ++++++++++ src/cmd/ksh93/include/version.h | 2 +- src/cmd/ksh93/sh/parse.c | 5 ++--- src/cmd/ksh93/tests/variables.sh | 9 +++++++++ 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/NEWS b/NEWS index 0fa8aabfa..6eb121f68 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,16 @@ For full details, see the git log at: Any uppercase BUG_* names are modernish shell bug IDs. +2020-06-04: + +- Fix BUG_KBGPID: the $! special parameter was not set if a background job + (somecommand &) or co-process (somecommand |&) was launched as the only + command within a braces block with an attached redirection, for example: + { + somecommand & + } >&2 + With the bug, $! was unchanged; now it contains the PID of somecommand. + 2020-05-31: - Fix a bug in autoloading functions. Directories in the path search list diff --git a/src/cmd/ksh93/include/version.h b/src/cmd/ksh93/include/version.h index ffbb19f82..be7f88eba 100644 --- a/src/cmd/ksh93/include/version.h +++ b/src/cmd/ksh93/include/version.h @@ -17,4 +17,4 @@ * David Korn * * * ***********************************************************************/ -#define SH_RELEASE "93u+m 2020-05-31" +#define SH_RELEASE "93u+m 2020-06-04" diff --git a/src/cmd/ksh93/sh/parse.c b/src/cmd/ksh93/sh/parse.c index 617504aff..7f259bc86 100644 --- a/src/cmd/ksh93/sh/parse.c +++ b/src/cmd/ksh93/sh/parse.c @@ -1360,11 +1360,10 @@ static Shnode_t *item(Lex_t *lexp,int flag) return(t); } sh_lex(lexp); + /* redirection(s) following a compound command */ if(io=inout(lexp,io,0)) { - if((tok=t->tre.tretyp&COMMSK) != TFORK) - tok = TSETIO; - t=makeparent(lexp,tok,t); + t=makeparent(lexp,TSETIO,t); t->tre.treio=io; } done: diff --git a/src/cmd/ksh93/tests/variables.sh b/src/cmd/ksh93/tests/variables.sh index 8627266bf..bf34b514e 100755 --- a/src/cmd/ksh93/tests/variables.sh +++ b/src/cmd/ksh93/tests/variables.sh @@ -558,6 +558,15 @@ set -- $x : & pid=$! ( : & ) [[ $pid == $! ]] || err_exit '$! value not preserved across subshells' + +pid=$! +{ : & } >&2 +[[ $pid == $! ]] && err_exit '$! value not updated after bg job in braces+redir' + +pid=$! +{ : |& } >&2 +[[ $pid == $! ]] && err_exit '$! value not updated after co-process in braces+redir' + unset foo typeset -A foo function foo.set