diff --git a/NEWS b/NEWS index b71a60547..7432ecc8c 100644 --- a/NEWS +++ b/NEWS @@ -3,6 +3,11 @@ For full details, see the git log at: https://github.com/ksh93/ksh Any uppercase BUG_* names are modernish shell bug IDs. +2021-04-15: + +- Fixed an optimization bug that caused the <>; redirection operator to fail + when used in -c scripts. + 2021-04-14: - Path-bound built-ins (such as /opt/ast/bin/cat) can now be executed by diff --git a/src/cmd/ksh93/include/version.h b/src/cmd/ksh93/include/version.h index dc4f25dd2..abbc3c7a3 100644 --- a/src/cmd/ksh93/include/version.h +++ b/src/cmd/ksh93/include/version.h @@ -20,7 +20,7 @@ #define SH_RELEASE_FORK "93u+m" /* only change if you develop a new ksh93 fork */ #define SH_RELEASE_SVER "1.0.0-alpha" /* semantic version number: https://semver.org */ -#define SH_RELEASE_DATE "2021-04-14" /* must be in this format for $((.sh.version)) */ +#define SH_RELEASE_DATE "2021-04-15" /* must be in this format for $((.sh.version)) */ #define SH_RELEASE_CPYR "(c) 2020-2021 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/main.c b/src/cmd/ksh93/sh/main.c index 4311597cf..86ca971f3 100644 --- a/src/cmd/ksh93/sh/main.c +++ b/src/cmd/ksh93/sh/main.c @@ -575,7 +575,7 @@ static void exfile(register Shell_t *shp, register Sfio_t *iop,register int fno) { execflags = sh_state(SH_ERREXIT)|sh_state(SH_INTERACTIVE); /* The last command may not have to fork */ - if(!sh_isstate(SH_PROFILE) && sh_isoption(SH_CFLAG) && + if(!sh_isstate(SH_PROFILE) && !sh_isstate(SH_INTERACTIVE) && (fno<0 || !(shp->fdstatus[fno]&(IOTTY|IONOSEEK))) && !sfreserve(iop,0,0)) { diff --git a/src/cmd/ksh93/sh/xec.c b/src/cmd/ksh93/sh/xec.c index 003031a1a..a1d334331 100644 --- a/src/cmd/ksh93/sh/xec.c +++ b/src/cmd/ksh93/sh/xec.c @@ -1003,8 +1003,8 @@ int sh_exec(register const Shnode_t *t, int flags) shp->exitval=0; shp->lastsig = 0; shp->lastpath = 0; - if(shp->exittrap || shp->errtrap) - execflg = 0; + if(shp->exittrap || shp->errtrap || (t->tre.treio && (t->tre.treio->iofile&IOREWRITE))) + execflg = 0; /* don't run the command with execve(2) */ switch(type&COMMSK) { case TCOM: diff --git a/src/cmd/ksh93/tests/builtins.sh b/src/cmd/ksh93/tests/builtins.sh index 184371d3f..544d8f9de 100755 --- a/src/cmd/ksh93/tests/builtins.sh +++ b/src/cmd/ksh93/tests/builtins.sh @@ -986,6 +986,9 @@ EOF # ====== # Builtins should handle unrecognized options correctly +# Note: To workaround https://github.com/ksh93/ksh/issues/165, put the list +# of builtins in a file, then read from that. +builtin > "$tmp/builtin-list" while IFS= read -r bltin <&3 do case $bltin in echo | test | true | false | \[ | : | getconf | */getconf | uname | */uname | catclose | catgets | catopen | Dt* | _Dt* | X* | login | newgrp ) @@ -999,7 +1002,7 @@ do case $bltin in esac [[ $actual == *"$expect"* ]] || err_exit "$bltin should show usage info on unrecognized options" \ "(expected string containing $(printf %q "$expect"), got $(printf %q "$actual"))" -done 3< <(builtin) +done 3< "$tmp/builtin-list" # ====== # The 'alarm' builtin could make 'read' crash due to IFS table corruption caused by unsafe asynchronous execution. diff --git a/src/cmd/ksh93/tests/io.sh b/src/cmd/ksh93/tests/io.sh index 06bbdc8a9..5581ead7b 100755 --- a/src/cmd/ksh93/tests/io.sh +++ b/src/cmd/ksh93/tests/io.sh @@ -500,12 +500,19 @@ actual=$(cat "$tmp/nums1") [[ "$actual" = "$expect" ]] || err_exit "Failed to truncate file in subshell \ (expected $(printf %q "$expect"), got $(printf %q "$actual"))" -: <<\INACTIVE # TODO: the >#5 is optimised away by a '-c' optimisation corner case bug +# The <>; redirection operator didn't work correctly in -c scripts +# https://github.com/att/ast/issues/9 "$SHELL" -c '1<>;"$1/nums2" >#5' x "$tmp" actual=$(cat "$tmp/nums2") [[ "$actual" = "$expect" ]] || err_exit "Failed to truncate file in -c script \ (expected $(printf %q "$expect"), got $(printf %q "$actual"))" -INACTIVE + +echo test > "$tmp/ast-9-reproducer" +"$SHELL" -c "echo x 1<>; \"$tmp/ast-9-reproducer\"" +exp=x +got=$(cat "$tmp/ast-9-reproducer") +[[ $exp == "$got" ]] || err_exit "<>; redirection operator fails in -c scripts \ +(expected $(printf %q "$exp"), got $(printf %q "$got"))" # ====== # Exit behaviour of 'exec', 'command exec', 'redirect' on redirections diff --git a/src/cmd/ksh93/tests/options.sh b/src/cmd/ksh93/tests/options.sh index 748575490..0ed56fc57 100755 --- a/src/cmd/ksh93/tests/options.sh +++ b/src/cmd/ksh93/tests/options.sh @@ -537,8 +537,12 @@ fi # SHOPT_BRACEPAT (set --default -o posix; [[ -o letoctal ]]) && err_exit "set --default failed to stop posix option from changing others" (set --posix; [[ -o letoctal ]]) || err_exit "set --posix fails to enable letoctal" (set -o posix; [[ -o letoctal ]]) || err_exit "set -o posix fails to enable letoctal" - $SHELL --posix < <(echo 'exit 0') || err_exit "ksh fails to handle --posix during startup" - $SHELL -o posix < <(echo 'exit 0') || err_exit "ksh fails to handle -o posix during startup" + + # Note: To workaround erratic behavior caused by https://github.com/ksh93/ksh/issues/165, + # avoid parsing the process substitutions with shcomp by running + # the tests with eval. + eval "$SHELL --posix < <(echo 'exit 0')" || err_exit "ksh fails to handle --posix during startup" + eval "$SHELL -o posix < <(echo 'exit 0')" || err_exit "ksh fails to handle -o posix during startup" fi # ====== diff --git a/src/cmd/ksh93/tests/signal.sh b/src/cmd/ksh93/tests/signal.sh index 3385d4527..a00111e24 100755 --- a/src/cmd/ksh93/tests/signal.sh +++ b/src/cmd/ksh93/tests/signal.sh @@ -450,6 +450,7 @@ let "$? == 256+9" && err_exit 'exit with status > 256 makes shell kill itself' cat >"$tmp/sigtest.sh" <<\EOF echo begin "$1" -c 'kill -9 "$$"' +# this extra comment disables an exec optimization EOF expect=$'^begin\n/.*/sigtest.sh: line 2: [1-9][0-9]*: Killed\n[1-9][0-9]{1,2}$' actual=$(LANG=C "$SHELL" -c '"$1" "$2" "$1"; echo "$?"' x "$SHELL" "$tmp/sigtest.sh" 2>&1) @@ -457,7 +458,8 @@ 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" +let "${actual##*$'\n'} > 128" || err_exit "child process signal did not cause exit status > 128" \ + "(got ${actual##*$'\n'})" # ====== # Killing a non-existent job shouldn't cause a segfault. Note that `2> /dev/null` has no effect when