1
0
Fork 0
mirror of git://git.code.sf.net/p/cdesktopenv/code synced 2025-02-15 04:32:24 +00:00

Fix process substitution combined with redirection (#40)

The code for handling process substitution with redirection was
never being run because IORAW is usually set when IOPROCSUB is
set. This commit fixes the problem by moving the required code
out of the !IORAW if statement. The following command now prints
'good' instead of writing 'ok' to a bizzare file:

$ ksh -c 'echo ok > >(sed s/ok/good/); wait'
good

This commit also fixes a bug that caused the process ID of the
asynchronous process to print when the shell was in interactive
mode. The following command no longer prints a process ID,
behaving like in Bash and zsh:

$ echo >(true)
/dev/fd/5

src/cmd/ksh93/sh/args.c:
 - Temporarily turn off the interactive state while in a process
   substitution to prevent the shell from printing the PID of
   the asynchronous process.

src/cmd/ksh93/sh/io.c:
 - Move the code for process substitution with redirection into
   a separate if statement.

src/cmd/ksh93/tests/io.sh:
 - Add two tests for both process substitution bugs fixed by this
   commit.

src/cmd/ksh93/tests/shtests:
 - Update shtests with a patch from Martijn Dekker to use
   pretty-printing for the output from the times builtin (if it
   is available).

Fixes #2
This commit is contained in:
Johnothan King 2020-06-23 15:02:16 -07:00 committed by GitHub
parent 1463236142
commit 0aa9e03f55
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 88 additions and 46 deletions

8
NEWS
View file

@ -3,6 +3,14 @@ For full details, see the git log at: https://github.com/ksh93/ksh
Any uppercase BUG_* names are modernish shell bug IDs.
2020-06-23:
- Fixed a bug that caused combining process substitution with redirection
to create a bizarre file in the user's current working directory.
- Using process substitution while the shell is interactive no longer
causes the process ID of the asynchronous process to be printed.
2020-06-22:
- The 'stop' and 'suspend' default aliases have been converted into regular

View file

@ -17,4 +17,4 @@
* David Korn <dgk@research.att.com> *
* *
***********************************************************************/
#define SH_RELEASE "93u+m 2020-06-22"
#define SH_RELEASE "93u+m 2020-06-23"

View file

@ -784,7 +784,7 @@ struct argnod *sh_argprocsub(Shell_t *shp,struct argnod *argp)
{
/* argument of the form <(cmd) or >(cmd) */
register struct argnod *ap;
int monitor, fd, pv[3];
int monitor, interactive, fd, pv[3];
int subshell = shp->subshell;
ap = (struct argnod*)stkseek(shp->stk,ARGVAL);
ap->argflag |= ARG_MAKE;
@ -805,8 +805,14 @@ struct argnod *sh_argprocsub(Shell_t *shp,struct argnod *argp)
sfputr(shp->stk,fmtbase((long)pv[fd],10,0),0);
ap = (struct argnod*)stkfreeze(shp->stk,0);
shp->inpipe = shp->outpipe = 0;
/* turn off job control */
if(interactive = (sh_isstate(SH_INTERACTIVE)!=0))
sh_offstate(SH_INTERACTIVE);
if(monitor = (sh_isstate(SH_MONITOR)!=0))
sh_offstate(SH_MONITOR);
/* do the process substitution */
shp->subshell = 0;
if(fd)
{
@ -818,9 +824,13 @@ struct argnod *sh_argprocsub(Shell_t *shp,struct argnod *argp)
shp->outpipe = pv;
sh_exec((Shnode_t*)argp->argchn.ap,(int)sh_isstate(SH_ERREXIT));
}
/* restore the previous state */
shp->subshell = subshell;
if(monitor)
sh_onstate(SH_MONITOR);
if(interactive)
sh_onstate(SH_INTERACTIVE);
#if SHOPT_DEVFD
close(pv[1-fd]);
sh_iosave(shp,-pv[fd], shp->topfd, (char*)0);

View file

@ -1182,21 +1182,21 @@ int sh_redirect(Shell_t *shp,struct ionod *iop, int flag)
strcpy(ap->argval,iop->ioname);
fname=sh_macpat(shp,ap,(iof&IOARITH)?ARG_ARITH:ARG_EXP);
}
else if(iof&IOPROCSUB)
{
struct argnod *ap = (struct argnod*)stakalloc(ARGVAL+strlen(iop->ioname));
memset(ap, 0, ARGVAL);
if(iof&IOPUT)
ap->argflag = ARG_RAW;
else if(shp->subshell)
sh_subtmpfile(shp);
ap->argchn.ap = (struct argnod*)fname;
ap = sh_argprocsub(shp,ap);
fname = ap->argval;
}
else
else if(!(iof&IOPROCSUB))
fname=sh_mactrim(shp,fname,(!sh_isoption(SH_NOGLOB)&&sh_isoption(SH_INTERACTIVE))?2:0);
}
if((iof&IOPROCSUB) && !(iof&IOLSEEK))
{
struct argnod *ap = (struct argnod*)stakalloc(ARGVAL+strlen(iop->ioname));
memset(ap, 0, ARGVAL);
if(iof&IOPUT)
ap->argflag = ARG_RAW;
else if(shp->subshell)
sh_subtmpfile(shp);
ap->argchn.ap = (struct argnod*)fname;
ap = sh_argprocsub(shp,ap);
fname = ap->argval;
}
errno=0;
np = 0;
#if SHOPT_COSHELL

View file

@ -539,5 +539,23 @@ actual=$(redirect ls 2>&1)
expect="*: redirect: incorrect syntax"
[[ $actual == $expect ]] || err_exit "redirect command wrongly accepting non-redir args"
# ======
# Process substitution
# An output process substitution should work when combined with a redirection.
# The 'cd "$tmp"' is because in many versions of ksh the test creates a bizarre
# file that isn't easy to delete individually.
cd "$tmp"
result=$("$SHELL" -c 'echo ok > >(sed s/ok/good/); wait')
[[ $result == good ]] || err_exit 'process substitution does not work with redirections' \
"(expected 'good', got $(printf %q "$result"))"
cd - >/dev/null
# Process substitution in an interactive shell shouldn't print the
# process ID of the asynchronous process.
result=$("$SHELL" -ic 'echo >(true) >/dev/null' 2>&1)
[[ -z $result ]] || err_exit 'interactive shells print a PID during process substitution' \
"(expected '', got $(printf %q "$result"))"
# ======
exit $((Errors<125?Errors:125))

View file

@ -10,7 +10,7 @@ valgrindflags='--xml=yes --log-file=/dev/null --track-origins=yes --read-var-inf
USAGE=$'
[-s8?
@(#)$Id: shtests (AT&T Research) 2012-05-29 $
@(#)$Id: shtests (AT&T Research/ksh93) 2020-06-23 $
]
'$USAGE_LICENSE$'
[+NAME?shtests - ksh regression test harness]
@ -273,16 +273,19 @@ then s=${SHELL:##*sh}
else SHCOMP=shcomp
fi
fi
tmp=$(
d=${TMPDIR:-/tmp}/ksh93.shtests.$$.${RANDOM:-0}
mkdir -m700 -- "$d" && CDPATH= cd -P -- "$d" && pwd
) || {
echo 'mkdir failed' >&2
exit 1
}
trap 'cd / && rm -rf "$tmp"' EXIT
if (( compile ))
then if whence $SHCOMP > /dev/null
then tmp=$(
d=${TMPDIR:-/tmp}/ksh93.shtests.$$.${RANDOM:-0}
mkdir -m700 -- "$d" && CDPATH= cd -P -- "$d" && pwd
) || {
echo 'mkdir failed' >&2
exit 1
}
trap 'cd / && rm -rf "$tmp"' EXIT
then :
elif (( compile > 1 ))
then echo $0: --compile: $SHCOMP not found >&2
exit 1
@ -293,16 +296,6 @@ if [[ $valgrind ]]
then if [[ -x $SHELL-g ]]
then SHELL=$SHELL-g
fi
if [[ ! $tmp ]]
then tmp=$(
d=${TMPDIR:-/tmp}/ksh93.shtests.$$.${RANDOM:-0}
mkdir -m700 -- "$d" && CDPATH= cd -P -- "$d" && pwd
) || {
echo 'mkdir failed' >&2
exit 1
}
trap 'cd / && rm -rf "$tmp"' EXIT
fi
valxml=$tmp/valgrind.xml
valgrind+=" --xml-file=$valxml"
fi
@ -393,17 +386,30 @@ do [[ $i == *.sh ]] || i+='.sh'
done
print "Total errors: $total_e"
# TODO: output process substitution is fatally broken.
# Until that is fixed, skip the pretty-printing.
# See https://github.com/modernish/ksh/issues/7
#print $'CPU time used:\n\\t user:\t system:'
#times > >(
# t[0]='main'
# read t[1] t[2]
# t[3]='*.sh'
# read t[4] t[5]
# printf '%s:\t%s\t%s\n' "${t[@]}"
#)
times
# This test harness should continue to work with old and buggy versions of ksh93, so check
# if we have the 'times' builtin and can use process substitution with output redirection.
# See: https://github.com/ksh93/ksh/commit/65d363fd
# https://github.com/ksh93/ksh/issues/2
if ( ulimit -t unlimited # fork to circumvent old ksh bugs
unalias times
PATH=/dev/null whence -q times || exit
cd "$tmp" || exit
echo ok > >(cat > procsubst_test)
wait
[[ $(< procsubst_test) == ok ]]
) 2>/dev/null
then # Transforming 'times' output requires a process substitution.
# A regular 'times | ...' pipeline would cause 'times' to be
# run in a subshell, which would reset all the times to zero.
times > >(
t[0]='CPU time' t[1]='user:' t[2]='system:'
t[3]='main:'; read t[4] t[5]
t[6]='tests:'; read t[7] t[8]
printf '%-8s%12s %12s\n' "${t[@]}"
)
wait "$!" # process substitutions are executed asynchronously
else # No pretty-printing.
times
fi
exit $((total_e > 125 ? 125 : total_e))