diff --git a/NEWS b/NEWS index 61f4c716a..3619dfef3 100644 --- a/NEWS +++ b/NEWS @@ -8,6 +8,10 @@ Any uppercase BUG_* names are modernish shell bug IDs. - The $LC_TIME variable is now recognized by ksh and if set to an invalid locale will show an error. +- Fixed BUG_CSUBSTDO: If standard output is closed before running a command + substitution, redirecting any other file descriptor no longer closes standard + output inside of the command substitution. + 2021-04-05: - Fixed a regression, introduced in ksh 93t+ 2009-07-31, that caused a command diff --git a/TODO b/TODO index 5719ff099..f6de0d4fe 100644 --- a/TODO +++ b/TODO @@ -23,12 +23,6 @@ https://github.com/modernish/modernish/tree/0.16/lib/modernish/cap/ initial ! (and, on some shells, ^) retains the meaning of negation, even in quoted strings within bracket patterns, including quoted variables. -- BUG_CSUBSTDO: If standard output (file descriptor 1) is closed before - entering a $(command substitution), and any other file descriptors are - redirected within the command substitution, commands such as 'echo' will - not work within the command substitution, acting as if standard output is - still closed. - - BUG_IFSGLOBS: In glob pattern matching (as in case or parameter substitution with # and %), if IFS starts with ? or * and the "$*" parameter expansion inserts any IFS separator characters, those characters diff --git a/src/cmd/ksh93/sh/io.c b/src/cmd/ksh93/sh/io.c index 436c8e0d8..249c3f51d 100644 --- a/src/cmd/ksh93/sh/io.c +++ b/src/cmd/ksh93/sh/io.c @@ -755,6 +755,7 @@ onintr(struct addrinfo* addr, void* handle) int sh_open(register const char *path, int flags, ...) { Shell_t *shp = sh_getinterp(); + Sfio_t *sp; register int fd = -1; mode_t mode; char *e; @@ -869,6 +870,16 @@ int sh_open(register const char *path, int flags, ...) mode = IOREAD; if(fd >= shp->gd->lim.open_max) sh_iovalidfd(shp,fd); + if((sp = shp->sftable[fd]) && (sfset(sp,0,0) & SF_STRING)) + { + int n,err=errno; + if((n = sh_fcntl(fd,F_DUPFD,10)) >= 10) + { + while(close(fd) < 0 && errno == EINTR) + errno = err; + fd = n; + } + } shp->fdstatus[fd] = mode; return(fd); } diff --git a/src/cmd/ksh93/tests/io.sh b/src/cmd/ksh93/tests/io.sh index 5bf72564f..44aee85e8 100755 --- a/src/cmd/ksh93/tests/io.sh +++ b/src/cmd/ksh93/tests/io.sh @@ -785,5 +785,15 @@ then "(expected $(printf %q "$expect"), got $(printf %q "$actual"))" fi +# ====== +# Test for BUG_CSUBSTDO: If stdout is closed before running a command substitution, +# redirecting any file descriptor in the command substitution would break stdout +# inside of the command substitution. This only occurred when redirecting any other +# file descriptor inside of the command substitution. +exp='Foo bar' +{ got=$(echo 'Foo bar' 2>/dev/null); } >&- +[[ $exp == $got ]] || err_exit "BUG_CSUBSTDO: Closing stdout outside of command substitution breaks stdout inside of command substitution" \ + "(expected $(printf %q "$exp"), got $(printf %q "$got"))" + # ====== exit $((Errors<125?Errors:125))