mirror of
git://git.code.sf.net/p/cdesktopenv/code
synced 2025-02-13 03:32:24 +00:00
Fix typeset attributes -a, -A, -l, -u leaking out of subshells
If an array or upper/lowercase variable was declared with a null initial value within a virtual/non-forked subshell, like: ( typeset -a foo; ... ) ( typeset -A foo; ... ) ( typeset -l foo; ... ) ( typeset -u foo; ... ) then the type declaration leaked out of the subshell into the parent shell environment, though without any values that may subsequently have been assigned. src/cmd/ksh93/bltins/typeset.c: setall(): - When deciding whether to create a virtual subshell scope for a variable, use sh_assignok(), which was actually designed for the purpose, instead of _nv_unset(). This allows getting rid of a tangled mess of special-casing that never worked quite right. src/cmd/ksh93/tests/arrays.sh: - Add regression tests checking that array declarations don't leak out of virtual subshells. src/cmd/ksh93/tests/attributes.sh: - Add regression tests for combining the 'export' and 'readonly' attributes with every other possible typeset attribute on unset variables. This also includes a subshell leak test for each one. Fixes: https://github.com/ksh93/ksh/issues/88
This commit is contained in:
parent
1bc2c74c74
commit
a2f13c19f2
4 changed files with 99 additions and 5 deletions
3
NEWS
3
NEWS
|
@ -15,6 +15,9 @@ Any uppercase BUG_* names are modernish shell bug IDs.
|
|||
an unrecognized option. 'sleep -: 1' will now show a usage message and
|
||||
exit instead of sleep for one second.
|
||||
|
||||
- Fixed a bug that caused the 'typeset' variable attributes -a, -A, -l, and
|
||||
-u to leak out of a subshell if they were set without assigning a value.
|
||||
|
||||
2020-07-23:
|
||||
|
||||
- Fixed an infinite loop that could occur when ksh is the system's /bin/sh.
|
||||
|
|
|
@ -691,13 +691,22 @@ static int setall(char **argv,register int flag,Dt_t *troot,struct tdata *tp
|
|||
if(!comvar && !iarray)
|
||||
continue;
|
||||
}
|
||||
if(!nv_isarray(np) && !strchr(name,'=') && !(shp->envlist && nv_onlist(shp->envlist,name)))
|
||||
|
||||
/* Create local scope for virtual subshell */
|
||||
if(shp->subshell)
|
||||
{
|
||||
if(comvar || (shp->last_root==shp->var_tree && (tp->tp || (!shp->st.real_fun && (nvflags&NV_STATIC)) || (!(flag&(NV_EXPORT|NV_RDONLY)) && nv_isattr(np,(NV_EXPORT|NV_IMPORT))==(NV_EXPORT|NV_IMPORT)))))
|
||||
{
|
||||
_nv_unset(np,0);
|
||||
}
|
||||
if(!nv_isattr(np,NV_NODISC|NV_ARRAY) && !nv_isvtree(np))
|
||||
{
|
||||
/*
|
||||
* Variables with internal trap/discipline functions (LC_*, LINENO, etc.) need to be
|
||||
* cloned, as moving them will remove the discipline function.
|
||||
*/
|
||||
np=sh_assignok(np,2);
|
||||
}
|
||||
else
|
||||
np=sh_assignok(np,0);
|
||||
}
|
||||
|
||||
if(troot==shp->var_tree)
|
||||
{
|
||||
if(iarray)
|
||||
|
|
|
@ -180,6 +180,12 @@ then err_exit 'arithmetic expressions in typeset not working'
|
|||
fi
|
||||
unset foo
|
||||
typeset foo=bar
|
||||
typeset -a foo
|
||||
if [[ ${foo[0]} != bar ]]
|
||||
then err_exit 'initial value not preserved when typecast to indexed array'
|
||||
fi
|
||||
unset foo
|
||||
typeset foo=bar
|
||||
typeset -A foo
|
||||
if [[ ${foo[0]} != bar ]]
|
||||
then err_exit 'initial value not preserved when typecast to associative'
|
||||
|
@ -674,5 +680,32 @@ actual=$("$SHELL" -c 'A[0]="'\''" B[0]=aa C[0]=aa; typeset -a') \
|
|||
[[ $actual == "$expect" ]] || err_exit 'Incorrect output when listing indexed array' \
|
||||
"(expected $(printf %q "$expect"), got $(printf %q "$actual"))"
|
||||
|
||||
# ======
|
||||
# Arrays in virtual/non-forked subshells
|
||||
|
||||
unset foo
|
||||
(typeset -a foo)
|
||||
[[ -n ${ typeset -p foo; } ]] && err_exit 'Null indexed array leaks out of subshell'
|
||||
|
||||
unset foo
|
||||
(typeset -a foo=(1 2 3))
|
||||
[[ -n ${ typeset -p foo; } ]] && err_exit 'Indexed array with init value leaks out of subshell'
|
||||
|
||||
unset foo
|
||||
(typeset -a foo; foo=(1 2 3))
|
||||
[[ -n ${ typeset -p foo; } ]] && err_exit 'Indexed array leaks out of subshell'
|
||||
|
||||
unset foo
|
||||
(typeset -A foo)
|
||||
[[ -n ${ typeset -p foo; } ]] && err_exit 'Null associative array leaks out of subshell'
|
||||
|
||||
unset foo
|
||||
(typeset -A foo=([bar]=baz [lorem]=ipsum))
|
||||
[[ -n ${ typeset -p foo; } ]] && err_exit 'Associative array with init value leaks out of subshell'
|
||||
|
||||
unset foo
|
||||
(typeset -A foo; foo=([bar]=baz [lorem]=ipsum))
|
||||
[[ -n ${ typeset -p foo; } ]] && err_exit 'Associative array leaks out of subshell'
|
||||
|
||||
# ======
|
||||
exit $((Errors<125?Errors:125))
|
||||
|
|
|
@ -468,4 +468,53 @@ typeset -Z2 foo=3
|
|||
export foo
|
||||
[[ $(typeset -p foo) == 'typeset -x -Z 2 -R 2 foo=03' ]] || err_exit '-Z2 not working after export'
|
||||
|
||||
# ======
|
||||
# unset exported readonly variables, combined with all other possible attributes
|
||||
typeset -A expect=(
|
||||
[a]='typeset -x -r -a foo'
|
||||
[b]='typeset -x -r -b foo'
|
||||
[i]='typeset -x -r -i foo'
|
||||
[i37]='typeset -x -r -i 37 foo'
|
||||
[l]='typeset -x -r -l foo'
|
||||
[n]='typeset -n -r foo'
|
||||
[s]='typeset -x -r -s -i 0 foo=0'
|
||||
[u]='typeset -x -r -u foo'
|
||||
[A]='typeset -x -r -A foo=()'
|
||||
[C]='typeset -x -r foo=()'
|
||||
[E]='typeset -x -r -E foo'
|
||||
[E12]='typeset -x -r -E 12 foo'
|
||||
[F]='typeset -x -r -F foo'
|
||||
[F12]='typeset -x -r -F 12 foo'
|
||||
[H]='typeset -x -r -H foo'
|
||||
[L]='typeset -x -r -L 0 foo'
|
||||
# [L17]='typeset -x -r -L 17 foo' # TODO: outputs '-L 0'
|
||||
[Mtolower]='typeset -x -r -l foo'
|
||||
[Mtoupper]='typeset -x -r -u foo'
|
||||
[R]='typeset -x -r -R 0 foo'
|
||||
# [R17]='typeset -x -r -R 17 foo' # TODO: outputs '-L 0'
|
||||
[X]='typeset -x -r -X 32 foo'
|
||||
[X17]='typeset -x -r -X 17 foo'
|
||||
[S]='typeset -x -r foo'
|
||||
[T]='typeset -x -r foo'
|
||||
[Z]='typeset -x -r -Z 0 -R 0 foo'
|
||||
# [Z13]='typeset -x -r -Z 13 -R 13 foo' # TODO: outputs 'typeset -x -r -Z 0 -R 0 foo'
|
||||
)
|
||||
for flag in a b i i37 l n s u A C E E12 F F12 H L Mtolower Mtoupper R X X17 S T Z
|
||||
do unset foo
|
||||
actual=$(
|
||||
redirect 2>&1
|
||||
export foo
|
||||
(typeset "-$flag" foo; readonly foo; typeset -p foo)
|
||||
typeset +x foo # unexport
|
||||
leak=${ typeset -p foo; }
|
||||
[[ -n $leak ]] && print "SUBSHELL LEAK: $leak"
|
||||
)
|
||||
if [[ $actual != "${expect[$flag]}" ]]
|
||||
then err_exit "unset exported readonly with -$flag:" \
|
||||
"expected $(printf %q "${expect[$flag]}"), got $(printf %q "$actual")"
|
||||
fi
|
||||
done
|
||||
unset expect
|
||||
|
||||
# ======
|
||||
exit $((Errors<125?Errors:125))
|
||||
|
|
Loading…
Reference in a new issue