1
0
Fork 0
mirror of git://git.code.sf.net/p/cdesktopenv/code synced 2025-03-09 15:50:02 +00:00

Fix field splitting bug triggered by DEBUG trap

An unquoted variable expansion evaluated in a DEBUG trap action
caused IFS field splitting to be deactivated in code executed after
the trap action. Thanks to Koichi Nakashima for the reproducer:

| v=''
| trap ': $v' DEBUG
| A="a b c"
| set -- $A
| printf '%s\n' "$@"
|
| Expected
|
| a
| b
| c
|
| Actual
|
| a b c

src/cmd/ksh93/sh/fault.c: sh_trap():
- Remove incorrect save/restore of sh.ifstable, the internal state
  table for field splitting. This reverts three lines added in ksh
  93t+ 2009-11-30. Analysis: As an expansion is split into fields
  (macro.c, lines 2367-2471), sh.ifstable is modified. If that
  happens within a DEBUG trap, any modifications in ifstable are
  undone by the restoring memccpy, leaving an inconsistent state.

src/cmd/ksh93/COMPATIBILITY:
- Document the DEBUG trap fixes, particularly the incorrect
  inheritance by subshells and functions that some scripts may now
  rely on because this bug is so longstanding. (re: 2a835a2d)

src/cmd/ksh93/tests/basic.sh:
- Add relevant tests.

Resolves: https://github.com/ksh93/ksh/issues/155

TODO: add a -T (-o functrace) option as in bash, which should allow
subshells and ksh-style functions to inherit DEBUG traps.

P.S.: The very handy multishell repo allows us to use 'git blame'
to trace the origin of the recently fixed DEBUG trap bugs.

The off-by-one error causing various bugs, reverted in 2a835a2d,
was introduced in ksh 93t 2008-07-25:
8e947ccf
(fault.c, line 321)

The incorrect check causing the exit status bug, reverted in
d00b4b39, was introduced in ksh 93t 2008-11-04:
b1ade268
(fault.c, line 459)

The ifstable save/restore causing the field splitting bug, reverted
in this commit, was introduced in ksh 93t+ 2009-11-30:
53d9f009
(fault.c, lines 440, 444, 482)

So all the bugs reported in #155 were fixed by simply reverting
these specific changes. I think that they are some experiments that
the developers simply forgot to remove. I've suspected such a thing
multiple times before. ksh93 was developed by researchers who were
genius innovators, but incredibly sloppy maintainers.
This commit is contained in:
Martijn Dekker 2021-01-24 15:46:46 +00:00
parent e664b78f98
commit 70368c57d6
5 changed files with 70 additions and 7 deletions

View file

@ -745,8 +745,9 @@ got=$(eval 'x=`for i in test; do case $i in test) true;; esac; done`' 2>&1) \
|| err_exit "case in a for loop inside a \`comsub\` caused syntax error (got $(printf %q "$got"))"
# ======
# Various DEBUG trap fixes: https://github.com/ksh93/ksh/issues/155
# Redirecting disabled the DEBUG trap
# https://github.com/ksh93/ksh/issues/155 (#1)
exp=$'LINENO: 4\nfoo\nLINENO: 5\nLINENO: 6\nbar\nLINENO: 7\nbaz'
got=$({ "$SHELL" -c '
PATH=/dev/null
@ -760,7 +761,6 @@ got=$({ "$SHELL" -c '
"(got status $e$( ((e>128)) && print -n / && kill -l "$e"), $(printf %q "$got"))"
# The DEBUG trap crashed when re-trapping inside a subshell
# https://github.com/ksh93/ksh/issues/155 (#2)
exp=$'trap -- \': main\' EXIT\ntrap -- \': main\' ERR\ntrap -- \': main\' KEYBD\ntrap -- \': main\' DEBUG'
got=$({ "$SHELL" -c '
PATH=/dev/null
@ -774,8 +774,20 @@ got=$({ "$SHELL" -c '
((!(e = $?))) && [[ $got == "$exp" ]] || err_exit 'Pseudosignal trap failed when re-trapping in subshell' \
"(got status $e$( ((e>128)) && print -n / && kill -l "$e"), $(printf %q "$got"))"
# Field splitting broke upon evaluating an unquoted expansion in a DEBUG trap
exp=$'a\nb\nc'
got=$({ "$SHELL" -c '
PATH=/dev/null
v=""
trap ": \$v" DEBUG
A="a b c"
set -- $A
printf "%s\n" "$@"
'; } 2>&1)
((!(e = $?))) && [[ $got == "$exp" ]] || err_exit 'Field splitting broke after executing DEBUG trap' \
"(got status $e$( ((e>128)) && print -n / && kill -l "$e"), $(printf %q "$got"))"
# The DEBUG trap had side effects on the exit status
# https://github.com/ksh93/ksh/issues/155 (#4)
trap ':' DEBUG
(exit 123)
(((e=$?)==123)) || err_exit "DEBUG trap run in subshell affects exit status (expected 123, got $e)"
@ -785,5 +797,46 @@ r=`exit 123`
(((e=$?)==123)) || err_exit "DEBUG trap run in \`comsub\` affects exit status (expected 123, got $e)"
trap - DEBUG
# The DEBUG trap was incorrectly inherited by subshells
exp=$'Subshell\nDebug 1\nParentshell'
got=$(
trap 'echo Debug ${.sh.subshell}' DEBUG
(echo Subshell)
echo Parentshell
)
trap - DEBUG # bug compat
[[ $got == "$exp" ]] || err_exit "DEBUG trap inherited by subshell" \
"(expected $(printf %q "$exp"), got $(printf %q "$got"))"
# The DEBUG trap was incorrectly inherited by ksh functions
exp=$'Debug 0\nFunctionEnv\nDebug 0\nParentEnv'
got=$(
function myfn
{
echo FunctionEnv
}
trap 'echo Debug ${.sh.level}' DEBUG
myfn
echo ParentEnv
)
trap - DEBUG # bug compat
[[ $got == "$exp" ]] || err_exit "DEBUG trap inherited by ksh function" \
"(expected $(printf %q "$exp"), got $(printf %q "$got"))"
# Make sure the DEBUG trap is still inherited by POSIX functions
exp=$'Debug 0\nDebug 1\nFunction\nDebug 0\nNofunction'
got=$(
myfn()
{
echo Function
}
trap 'echo Debug ${.sh.level}' DEBUG
myfn
echo Nofunction
)
trap - DEBUG # bug compat
[[ $got == "$exp" ]] || err_exit "DEBUG trap not inherited by POSIX function" \
"(expected $(printf %q "$exp"), got $(printf %q "$got"))"
# ======
exit $((Errors<125?Errors:125))