mirror of
git://git.code.sf.net/p/cdesktopenv/code
synced 2025-03-09 15:50:02 +00:00
Fix incorrect exec optimisation with monitor/pipefail on
Reproducer script:
tempfile=/tmp/out2.$$.$RANDOM
bintrue=$(whence -p true)
for opt in monitor pipefail
do
(
set +x -o "$opt"
(
sleep .05
echo "ok $opt" >&2
) 2>$tempfile | "$bintrue"
) &
wait
cat "$tempfile"
rm -f "$tempfile"
done
Expected output:
ok monitor
ok pipefail
Actual output:
(none)
The 'monitor' and 'pipefail' options are supposed to make the shell
wait for the all commands in the pipeline to terminate and not only
the last component, regardless of whether the pipe between the
component commands is still open. In the failing reproducer, the
dummy external true command is subject to an exec optimization, so
it replaces the subshell instead of forking a new process. This is
incorrect, as the shell is no longer around to wait for the
left-hand part of the pipeline, so it continues in the background
without being waited for. Since it writes to standard error after
.05 seconds (after the pipe is closed), the 'cat' command reliably
finds the temp file empty. Without the sleep this would be a race
condition with unpredictable results.
Interestingly, this bug is only triggered for a (background
subshell)& and not for a forked (regular subshell). Which means the
exec optimization is not done for a forked regular subshell, though
there is no reason not to. That will be fixed in the next commit.
src/cmd/ksh93/sh/xec.c: sh_exec():
- case TFORK: Never allow an exec optimization if we're running a
command in a multi-command pipeline (pipejob is set) and the
shell needs to wait for all pipeline commands, i.e.: either the
time keyword is in use, the SH_MONITOR state is active, or the
SH_PIPEFAIL option is on.
- case TFIL: Fix the logic for setting job.waitall for the
non-SH_PIPEFAIL case. Do not 'or' in the boolean value but assign
it, and include the SH_TIMING (time keyword in use) state too.
- case TTIME: After that fix in case TFIL, we don't need to bother
setting job.waitall explicitly here.
src/cmd/ksh93/sh.1:
- Add missing documentation for the conditions where the shell
waits for all pipeline components (time, -o monitor/pipefail).
Resolves: https://github.com/ksh93/ksh/issues/449
This commit is contained in:
parent
6016fb64ce
commit
16b3802148
5 changed files with 56 additions and 14 deletions
|
|
@ -605,5 +605,25 @@ EOF
|
|||
exit
|
||||
EOF
|
||||
|
||||
# ======
|
||||
# https://github.com/ksh93/ksh/issues/449
|
||||
set +o monitor +o pipefail
|
||||
for opt in monitor pipefail
|
||||
do
|
||||
outfile=out$opt
|
||||
exp="ok $opt"
|
||||
(
|
||||
set +x -o "$opt"
|
||||
(
|
||||
sleep .01
|
||||
print "$exp" >&2
|
||||
) 2>$outfile | "${ whence -p true; }" # the external 'true' should not be exec-optimized
|
||||
) &
|
||||
wait "$!"
|
||||
got=$(<$outfile)
|
||||
[[ $got == "$exp" ]] || err_exit "shell did not wait for entire pipeline with -o $opt" \
|
||||
"(expected $(printf %q "$exp"), got $(printf %q "$got"))"
|
||||
done
|
||||
|
||||
# ======
|
||||
exit $((Errors<125?Errors:125))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue