diff --git a/NEWS b/NEWS index e797fbc0173f..fc958b256bef 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,12 @@ This documents significant changes in the dev branch of ksh 93u+m. For full details, see the git log at: https://github.com/ksh93/ksh Uppercase BUG_* IDs are shell bug IDs as used by the Modernish shell library. +2023-12-28: + +- Fixed intermittent incorrect behaviour (a race condition), introduced on + 2023-09-15, that occurred on some systems when running an external command + with a redirection from a command substitution. + 2023-12-25: - Fixed a regression in the behavior of 'exit' in a trap action, introduced diff --git a/src/cmd/ksh93/include/version.h b/src/cmd/ksh93/include/version.h index 5df715d9f4c1..f7245b4fb4a0 100644 --- a/src/cmd/ksh93/include/version.h +++ b/src/cmd/ksh93/include/version.h @@ -18,7 +18,7 @@ #define SH_RELEASE_FORK "93u+m" /* only change if you develop a new ksh93 fork */ #define SH_RELEASE_SVER "1.1.0-alpha" /* semantic version number: https://semver.org */ -#define SH_RELEASE_DATE "2023-12-25" /* must be in this format for $((.sh.version)) */ +#define SH_RELEASE_DATE "2023-12-28" /* must be in this format for $((.sh.version)) */ #define SH_RELEASE_CPYR "(c) 2020-2023 Contributors to ksh " SH_RELEASE_FORK /* Scripts sometimes field-split ${.sh.version}, so don't change amount of whitespace. */ diff --git a/src/cmd/ksh93/sh/io.c b/src/cmd/ksh93/sh/io.c index 08233715e00b..2b08a9e342a2 100644 --- a/src/cmd/ksh93/sh/io.c +++ b/src/cmd/ksh93/sh/io.c @@ -1135,28 +1135,39 @@ int sh_redirect(struct ionod *iop, int flag) clexec = 1; if(iop) traceon = sh_trace(NULL,0); - for(;iop;iop=iop->ionxt) - { - iof=iop->iofile; - fn = (iof&IOUFD); - /* - * A command substitution will hang on exit, writing infinite '\0', if, - * within it, standard output (FD 1) is redirected for a built-in command - * that calls sh_subfork(), or redirected permanently using 'exec' or - * 'redirect'. This forking workaround is necessary to avoid that bug. - * For shared-state comsubs, forking is incorrect, so error out then. - * TODO: actually fix the bug and remove this workaround. - */ - if(fn==1 && sh.subshell && sh.comsub) + /* + * A command substitution will hang on exit, writing infinite '\0', if, + * within it, standard output (FD 1) is redirected for a built-in command + * that calls sh_subfork(), or redirected permanently using 'exec' or + * 'redirect'. This forking workaround is necessary to avoid that bug. + * For shared-state comsubs, forking is incorrect, so error out then. + * TODO: actually fix the bug and remove this workaround. + * (Note that sh.redir0 is set to 1 in xec.c immediately before processing + * redirections for any built-in command, including 'exec' and 'redirect'.) + */ + if(sh.subshell && sh.comsub && sh.redir0==1) + { + struct ionod *i; + for(i = iop; i; i = i->ionxt) { + if((i->iofile & IOUFD) != 1) + continue; if(!sh.subshare) + { sh_subfork(); - else if(flag==1 || flag==2) /* block stdout perma-redirects: would hang */ + break; + } + if(flag==1 || flag==2) { errormsg(SH_DICT,ERROR_exit(1),"cannot redirect stdout inside shared-state comsub"); UNREACHABLE(); } } + } + for(; iop; iop = iop->ionxt) + { + iof = iop->iofile; + fn = (iof & IOUFD); if(sh.redir0 && fn==0 && !(iof&IOMOV)) sh.redir0 = 2; io_op[0] = '0'+(iof&IOUFD);