mirror of
git://git.code.sf.net/p/cdesktopenv/code
synced 2025-03-09 15:50:02 +00:00
tests/leaks.sh: redesign with a more robust testing algorithm
On modern operating systems, memory management is non-deterministic (i.e. random, unpredictable) to varying degrees. This makes testing for memory leaks a nightmare as the OS may decide to randomly grow a process's memory allocation at any time for no apparent reason, causing intermittent test failures that do not represent real memory leaks. So far, the leaks test tried to cope with this by using a large number of iterations plus a certain amount of bytes of tolerance per iteration. This was inefficient and on some systems still did not fully eliminate intermittent test failures. This commit introduces a new testing algorithm that is designed to cope with a large degree of unpredictability. Instead of a fixed number of test iterations, it defines a maximum (16384), dividing them in blocks of 128 iterations. It also defines a minimum number of sequential "good" iteration blocks, counted if memory usage did not increase from one block to the next. That minimum number is set to 16. The theory is that if we can get 16 "good" iteration blocks in a row, we can safely assume it's not a real memory leak, break the loop, and consider the test succeeded. That "good" sequence is allowed to occur at any point in the loop, creating a high built-in tolerance for non-deterministic shenanigans. It also speeds up the tests, as successful tests can bow out at 16 * 128 == 2048 iterations if they're lucky. If the OS decides to randomly grow the memory heap, it may take more tries, but almost (?) certainly not more than the maximum 16384 (128 blocks). If the counter reaches that, then we assume a memory leak and throw a test failure. We're also no longer testing with byte granularity in any case; the randomness of memory management makes that pointless. All getmem() function versions now return kibibytes (1024 bytes). This should eliminate the need for workarounds such as initial iterations to "steady the state" or a tolerance of a certain number of bytes. I've experimentally determined the exact values (max_iter, block_iter, min_good_blocks) that seem to work reliably on all systems I've tested. They are easy to tweak if necessary. To make all this manageable, this commit hides all the supporting code in a triplet of aliases (TEST, DO, DONE) that, when used correctly, create a grammatically robust shell code block: you can add redirections, pipe into it, etc. as expected. This makes the actual tests a great deal easier to read as well. src/cmd/ksh93/tests/pty.sh: - Implement new leaks testing framework as described and convert all the tests to it. - Mark known leaks with a 'known' variable. Print non-fail warnings for all known leaks, but skip the tests by default. Test them only if DEBUG is exported. This is better than commenting them out as we will no longer be tempted to forget about these. - Move the test for large command substitutions to subshell.sh -- it's not in fact a leak test; instead, it checks that command substitutions don't lose data. src/cmd/ksh93/tests/_common: err_exit(): - Since we're printing more warnings, clearly mark all test failures with 'FAIL:' to make them stand out. src/cmd/ksh93/tests/shtests. src/cmd/ksh93/tests/pty.sh: - Special-case leaks.sh for counting tests; grep ^TEST. - Special-case pty.sh as well while we're at it by grepping tst() calls. Remove all the dummy '# err_exit #' comments from pty.sh as they are now no longer used for counting the tests.
This commit is contained in:
parent
a9c6f77c3e
commit
db3a3d8fc0
5 changed files with 259 additions and 369 deletions
|
@ -21,7 +21,7 @@ _message()
|
||||||
}
|
}
|
||||||
function err_exit
|
function err_exit
|
||||||
{
|
{
|
||||||
_message "$@"
|
_message "$1" "FAIL:" "${@:2}"
|
||||||
let Errors+=1
|
let Errors+=1
|
||||||
}
|
}
|
||||||
alias err_exit='err_exit $LINENO' # inaccurate err_exit name kept for historical integrity :)
|
alias err_exit='err_exit $LINENO' # inaccurate err_exit name kept for historical integrity :)
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
# Florham Park NJ #
|
# Florham Park NJ #
|
||||||
# #
|
# #
|
||||||
# David Korn <dgk@research.att.com> #
|
# David Korn <dgk@research.att.com> #
|
||||||
|
# Martijn Dekker <martijn@inlv.org> #
|
||||||
# #
|
# #
|
||||||
########################################################################
|
########################################################################
|
||||||
|
|
||||||
|
@ -27,31 +28,22 @@
|
||||||
if builtin vmstate 2>/dev/null &&
|
if builtin vmstate 2>/dev/null &&
|
||||||
n=$(vmstate --format='%(busy_size)u') &&
|
n=$(vmstate --format='%(busy_size)u') &&
|
||||||
let "($n) == ($n) && n > 0" # non-zero number?
|
let "($n) == ($n) && n > 0" # non-zero number?
|
||||||
then N=512 # number of iterations for each test
|
then vmalloc=enabled
|
||||||
unit=bytes
|
getmem()
|
||||||
tolerance=$((4*N)) # tolerate 4 bytes per iteration to account for vmalloc artefacts
|
|
||||||
vmalloc=enabled
|
|
||||||
function getmem
|
|
||||||
{
|
{
|
||||||
vmstate --format='%(busy_size)u'
|
print $(( $(vmstate --format='%(busy_size)u') / 1024 ))
|
||||||
}
|
}
|
||||||
# On Linux, we can use /proc to get byte granularity for vsize (field 23).
|
# On Linux, we can use /proc to get byte granularity for vsize (field 23).
|
||||||
elif [[ -f /proc/$$/stat && $(uname) == Linux ]]
|
elif [[ -f /proc/$$/stat && $(uname) == Linux ]]
|
||||||
then N=4096 # number of iterations for each test
|
then getmem()
|
||||||
unit=bytes
|
|
||||||
tolerance=$((16*N)) # tolerate 16 bytes per iteration to account for malloc artefacts
|
|
||||||
function getmem
|
|
||||||
{
|
{
|
||||||
cut -f 23 -d ' ' </proc/$$/stat
|
print $(( $(cut -f 23 -d ' ' </proc/$$/stat ) / 1024 ))
|
||||||
}
|
}
|
||||||
# On UnixWare, read the process virtual size with ps
|
# On UnixWare, read the process virtual size with ps
|
||||||
elif [[ $(uname) == UnixWare ]] &&
|
elif [[ $(uname) == UnixWare ]] &&
|
||||||
n=$(ps -o vsz= -p "$$" 2>/dev/null) &&
|
n=$(ps -o vsz= -p "$$" 2>/dev/null) &&
|
||||||
let "($n) == ($n) && n > 0"
|
let "($n) == ($n) && n > 0"
|
||||||
then N=16384
|
then getmem()
|
||||||
unit=KiB
|
|
||||||
tolerance=$((4*N/1024)) # tolerate 4 bytes per iteration to account for malloc artefacts
|
|
||||||
function getmem
|
|
||||||
{
|
{
|
||||||
ps -o vsz= -p "$$"
|
ps -o vsz= -p "$$"
|
||||||
}
|
}
|
||||||
|
@ -59,10 +51,7 @@ then N=16384
|
||||||
# of the 'ps' command (the standard 'vsz', virtual size, is not usable).
|
# of the 'ps' command (the standard 'vsz', virtual size, is not usable).
|
||||||
elif n=$(ps -o rss= -p "$$" 2>/dev/null) &&
|
elif n=$(ps -o rss= -p "$$" 2>/dev/null) &&
|
||||||
let "($n) == ($n) && n > 0"
|
let "($n) == ($n) && n > 0"
|
||||||
then N=16384
|
then getmem()
|
||||||
unit=KiB
|
|
||||||
tolerance=$((12*N/1024)) # tolerate 12 bytes per iteration to account for malloc/ps artefacts
|
|
||||||
function getmem
|
|
||||||
{
|
{
|
||||||
ps -o rss= -p "$$"
|
ps -o rss= -p "$$"
|
||||||
}
|
}
|
||||||
|
@ -70,79 +59,104 @@ else warning 'cannot find method to measure memory usage; skipping tests'
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# test for variable reset leak #
|
# Parameters for test blocks.
|
||||||
|
# Intended to cope with all non-deterministic OS memory management artefacts.
|
||||||
|
#
|
||||||
|
# Theory: if we can get a sequence of $min_good_blocks blocks of $block_iter iterations without the memory state changing,
|
||||||
|
# then we can safely assume it's not a memory leak, break the loop, and consider the test succeeded. To allow for
|
||||||
|
# unpredictable OS memory management artefacts, that sequence is allowed to occur anywhere within $max_iter iterations.
|
||||||
|
# This speeds up the tests, as successful tests can bow out at $((min_good_blocks * block_iter)) iterations if they're
|
||||||
|
# lucky. If the OS decides to randomly grow the memory heap, it may take more tries, but hopefully not more than
|
||||||
|
# $max_iter iterations. If the loop counter reaches $max_iter, then we assume a memory leak and throw a test failure.
|
||||||
|
|
||||||
function test_reset
|
typeset -ir max_iter=16384 block_iter=128 min_good_blocks=16
|
||||||
{
|
|
||||||
integer i N=$1
|
|
||||||
|
|
||||||
for ((i = 0; i < N; i++))
|
# Set up test block construct.
|
||||||
do u=$i
|
# Known leaks can be marked known=y to turn them into non-fail warnings.
|
||||||
done
|
#
|
||||||
}
|
# Usage:
|
||||||
|
# TEST title='description' [ known=y [ url=<issue tracker URL> ] ]
|
||||||
|
# <optional preparatory commands>
|
||||||
|
# DO
|
||||||
|
# <test payload commands>
|
||||||
|
# DONE
|
||||||
|
#
|
||||||
|
# To avoid messing up $LINENO, aliases should not contain newline characters.
|
||||||
|
# To keep things readable, backslash line continuation is used instead.
|
||||||
|
|
||||||
# Initialise variables used below to avoid false leaks
|
typeset .lt # create lt (leak test) namespace for internal variables
|
||||||
before=0 after=0 i=0 u=0
|
typeset -i .lt.before=0 .lt.after=0 .lt.total=0 .lt.good=0 .lt.i=0 .lt.j=0
|
||||||
|
alias TEST=\
|
||||||
|
'for .lt.i in 1; do '\
|
||||||
|
' unset -v known url; '
|
||||||
|
# optional preparatory commands go here
|
||||||
|
alias DO=\
|
||||||
|
' if [[ -v known && ! -v DEBUG ]]; '\
|
||||||
|
' then warning "skipping test for known leak \"$title\";" '\
|
||||||
|
' "export DEBUG=y to test" ${url:+"and help us fix it at: $url"}; '\
|
||||||
|
' break; '\
|
||||||
|
' fi; '\
|
||||||
|
' .lt.before=$(getmem) .lt.good=0 .lt.total=0; '\
|
||||||
|
' for ((.lt.i = 0; .lt.i < max_iter; .lt.i += block_iter)); '\
|
||||||
|
' do for ((.lt.j = 0; .lt.j < block_iter; .lt.j++)); '\
|
||||||
|
' do '
|
||||||
|
# test payload commands go here
|
||||||
|
alias DONE=\
|
||||||
|
' done; '\
|
||||||
|
' .lt.after=$(getmem); '\
|
||||||
|
' if ((.lt.after <= .lt.before)); '\
|
||||||
|
' then ((.lt.good++ == min_good_blocks)) && break; '\
|
||||||
|
' else ((.lt.good = 0)); '\
|
||||||
|
' ((.lt.total += (.lt.after - .lt.before))); '\
|
||||||
|
' .lt.before=$(getmem); '\
|
||||||
|
' fi; '\
|
||||||
|
' done; '\
|
||||||
|
' if ((.lt.i >= max_iter)); '\
|
||||||
|
' then if [[ -v known ]]; '\
|
||||||
|
' then err_exit "known leak: $title: leaked approx ${.lt.total} KiB after ${.lt.i} iterations" '\
|
||||||
|
' ${url:+"-- help us fix it at: $url"}; '\
|
||||||
|
' else err_exit "$title: leaked approx ${.lt.total} KiB after ${.lt.i} iterations"; '\
|
||||||
|
' fi; '\
|
||||||
|
' elif [[ -v known ]]; '\
|
||||||
|
' then warning "did not detect known leak \"$title\": succeeded after ${.lt.i} iterations)" ${url:+"-- see: $url"}; '\
|
||||||
|
' elif [[ -v DEBUG ]]; '\
|
||||||
|
' then _message "$LINENO" "[DEBUG] test \"$title\" succeeded after ${.lt.i} iterations"; '\
|
||||||
|
' fi; '\
|
||||||
|
'done'
|
||||||
|
|
||||||
|
# ____ Begin memory leak tests ____
|
||||||
|
|
||||||
# Check results.
|
TEST title='variable value reset'
|
||||||
# The function has 'err_exit' in the name so that shtests counts each call as a test.
|
integer i=0
|
||||||
function err_exit_if_leak
|
u=foo
|
||||||
{
|
DO
|
||||||
if ((after > before + tolerance))
|
u=$((++i))
|
||||||
then err\_exit "$1" "$2 (leaked approx $((after - before)) $unit after $N iterations)"
|
DONE
|
||||||
fi
|
|
||||||
}
|
|
||||||
alias err_exit_if_leak='err_exit_if_leak "$LINENO"'
|
|
||||||
|
|
||||||
# one round to get to steady state -- sensitive to -x
|
|
||||||
|
|
||||||
test_reset $N
|
|
||||||
test_reset $N
|
|
||||||
before=$(getmem)
|
|
||||||
test_reset $N
|
|
||||||
after=$(getmem)
|
|
||||||
err_exit_if_leak "variable value reset memory leak"
|
|
||||||
|
|
||||||
# buffer boundary tests
|
|
||||||
|
|
||||||
for exp in 65535 65536
|
|
||||||
do got=$($SHELL -c 'x=$(printf "%.*c" '$exp' x); print ${#x}' 2>&1)
|
|
||||||
[[ $got == $exp ]] || err_exit "large command substitution failed -- expected $exp, got $got"
|
|
||||||
done
|
|
||||||
|
|
||||||
|
# data for the next two tests...
|
||||||
data="(v=;sid=;di=;hi=;ti='1328244300';lv='o';id='172.3.161.178';var=(k='conn_num._total';u=;fr=;l='Number of Connections';n='22';t='number';))"
|
data="(v=;sid=;di=;hi=;ti='1328244300';lv='o';id='172.3.161.178';var=(k='conn_num._total';u=;fr=;l='Number of Connections';n='22';t='number';))"
|
||||||
read -C stat <<< "$data"
|
read -C stat <<< "$data"
|
||||||
for ((i=0; i < 8; i++)) # steady state first
|
|
||||||
do print -r -- "$data" | while read -u$n -C stat; do :; done {n}<&0-
|
|
||||||
done
|
|
||||||
before=$(getmem)
|
|
||||||
for ((i=0; i < N; i++))
|
|
||||||
do print -r -- "$data"
|
|
||||||
done | while read -u$n -C stat
|
|
||||||
do :
|
|
||||||
done {n}<&0-
|
|
||||||
after=$(getmem)
|
|
||||||
err_exit_if_leak "memory leak with read -C when deleting compound variable"
|
|
||||||
|
|
||||||
# extra 'read's to get to steady state
|
while :
|
||||||
for ((i=0; i < 10; i++))
|
do print -r -- "$data"
|
||||||
do read -C stat <<< "$data"
|
done | \
|
||||||
done
|
TEST title='read -C when deleting compound variable'
|
||||||
before=$(getmem)
|
DO read -u$n -C stat
|
||||||
for ((i=0; i < N; i++))
|
DONE {n}<&0-
|
||||||
do read -C stat <<< "$data"
|
|
||||||
done
|
TEST title='read -C when using <<<'
|
||||||
after=$(getmem)
|
DO
|
||||||
err_exit_if_leak "memory leak with read -C when using <<<"
|
read -C stat <<< "$data"
|
||||||
|
DONE
|
||||||
|
|
||||||
|
unset data stat
|
||||||
|
|
||||||
# ======
|
# ======
|
||||||
# Unsetting an associative array shouldn't cause a memory leak
|
# Unsetting an associative array shouldn't cause a memory leak
|
||||||
# See https://www.mail-archive.com/ast-users@lists.research.att.com/msg01016.html
|
# See https://www.mail-archive.com/ast-users@lists.research.att.com/msg01016.html
|
||||||
typeset -A stuff
|
TEST title='unset of associative array'
|
||||||
before=$(getmem)
|
typeset -A stuff
|
||||||
for (( i=0; i < N; i++ ))
|
DO
|
||||||
do
|
|
||||||
unset stuff[xyz]
|
unset stuff[xyz]
|
||||||
typeset -A stuff[xyz]
|
typeset -A stuff[xyz]
|
||||||
stuff[xyz][elem0]="data0"
|
stuff[xyz][elem0]="data0"
|
||||||
|
@ -150,106 +164,82 @@ do
|
||||||
stuff[xyz][elem2]="data2"
|
stuff[xyz][elem2]="data2"
|
||||||
stuff[xyz][elem3]="data3"
|
stuff[xyz][elem3]="data3"
|
||||||
stuff[xyz][elem4]="data4"
|
stuff[xyz][elem4]="data4"
|
||||||
done
|
DONE
|
||||||
unset stuff
|
|
||||||
after=$(getmem)
|
# https://github.com/ksh93/ksh/issues/94
|
||||||
err_exit_if_leak 'unset of associative array causes memory leak'
|
TEST title='defining associative array in subshell' known=y url=https://github.com/ksh93/ksh/issues/94
|
||||||
|
DO
|
||||||
|
(typeset -A foo=([a]=1 [b]=2 [c]=3))
|
||||||
|
DONE
|
||||||
|
|
||||||
# ======
|
# ======
|
||||||
# Memory leak when resetting PATH and clearing hash table
|
# Memory leak when resetting PATH and clearing hash table
|
||||||
# ...steady memory state:
|
|
||||||
command -v ls >/dev/null # add something to hash table
|
|
||||||
PATH=/dev/null true # set/restore PATH & clear hash table
|
|
||||||
# ...test for leak:
|
# ...test for leak:
|
||||||
before=$(getmem)
|
TEST title='PATH reset before PATH search'
|
||||||
for ((i=0; i < N; i++))
|
DO
|
||||||
do PATH=/dev/null true # set/restore PATH & clear hash table
|
PATH=/dev/null true # set/restore PATH & clear hash table
|
||||||
command -v ls # do PATH search, add to hash table
|
command -v ls # do PATH search, add to hash table
|
||||||
done >/dev/null
|
DONE >/dev/null
|
||||||
after=$(getmem)
|
|
||||||
err_exit_if_leak 'memory leak on PATH reset before PATH search'
|
|
||||||
# ...test for another leak that only shows up when building with nmake:
|
# ...test for another leak that only shows up when building with nmake:
|
||||||
before=$(getmem)
|
TEST title='PATH reset'
|
||||||
for ((i=0; i < N; i++))
|
DO
|
||||||
do PATH=/dev/null true # set/restore PATH & clear hash table
|
PATH=/dev/null true # set/restore PATH & clear hash table
|
||||||
done >/dev/null
|
DONE >/dev/null
|
||||||
after=$(getmem)
|
|
||||||
err_exit_if_leak 'memory leak on PATH reset'
|
|
||||||
|
|
||||||
# ======
|
# ======
|
||||||
# Defining a function in a virtual subshell
|
# Defining a function in a virtual subshell
|
||||||
# https://github.com/ksh93/ksh/issues/114
|
# https://github.com/ksh93/ksh/issues/114
|
||||||
|
|
||||||
unset -f foo
|
TEST title='ksh function defined in virtual subshell'
|
||||||
before=$(getmem)
|
unset -f foo
|
||||||
for ((i=0; i < N; i++))
|
DO
|
||||||
do (function foo { :; }; foo)
|
(function foo { :; }; foo)
|
||||||
done
|
DONE
|
||||||
after=$(getmem)
|
|
||||||
err_exit_if_leak 'ksh function defined in virtual subshell'
|
|
||||||
typeset -f foo >/dev/null && err_exit 'ksh function leaks out of subshell'
|
|
||||||
|
|
||||||
unset -f foo
|
TEST title='POSIX function defined in virtual subshell'
|
||||||
before=$(getmem)
|
unset -f foo
|
||||||
for ((i=0; i < N; i++))
|
DO
|
||||||
do (foo() { :; }; foo)
|
(foo() { :; }; foo)
|
||||||
done
|
DONE
|
||||||
after=$(getmem)
|
|
||||||
err_exit_if_leak 'POSIX function defined in virtual subshell'
|
|
||||||
typeset -f foo >/dev/null && err_exit 'POSIX function leaks out of subshell'
|
|
||||||
|
|
||||||
# Unsetting a function in a virtual subshell
|
# Unsetting a function in a virtual subshell
|
||||||
|
|
||||||
function foo { echo bar; }
|
TEST title='ksh function unset in virtual subshell'
|
||||||
before=$(getmem)
|
function foo { echo bar; }
|
||||||
for ((i=0; i < N; i++))
|
DO
|
||||||
do (unset -f foo)
|
(unset -f foo)
|
||||||
done
|
DONE
|
||||||
after=$(getmem)
|
|
||||||
err_exit_if_leak 'ksh function unset in virtual subshell'
|
|
||||||
typeset -f foo >/dev/null || err_exit 'ksh function unset in subshell was unset in main shell'
|
|
||||||
|
|
||||||
foo() { echo bar; }
|
TEST title='POSIX function unset in virtual subshell'
|
||||||
before=$(getmem)
|
foo() { echo bar; }
|
||||||
for ((i=0; i < N; i++))
|
DO
|
||||||
do (unset -f foo)
|
(unset -f foo)
|
||||||
done
|
DONE
|
||||||
after=$(getmem)
|
|
||||||
err_exit_if_leak 'POSIX function unset in virtual subshell'
|
|
||||||
typeset -f foo >/dev/null || err_exit 'POSIX function unset in subshell was unset in main shell'
|
|
||||||
|
|
||||||
before=$(getmem)
|
TEST title='ksh function defined and unset in virtual subshell'
|
||||||
for ((i=0; i < N; i++))
|
DO
|
||||||
do (function foo { echo baz; }; unset -f foo)
|
(function foo { echo baz; }; unset -f foo)
|
||||||
done
|
DONE
|
||||||
after=$(getmem)
|
|
||||||
err_exit_if_leak 'ksh function defined and unset in virtual subshell'
|
|
||||||
|
|
||||||
before=$(getmem)
|
TEST title='POSIX function defined and unset in virtual subshell'
|
||||||
for ((i=0; i < N; i++))
|
DO
|
||||||
do (foo() { echo baz; }; unset -f foo)
|
(foo() { echo baz; }; unset -f foo)
|
||||||
done
|
DONE
|
||||||
after=$(getmem)
|
|
||||||
err_exit_if_leak 'POSIX function defined and unset in virtual subshell'
|
|
||||||
|
|
||||||
# ======
|
# ======
|
||||||
# Sourcing a dot script in a virtual subshell
|
# Sourcing a dot script in a virtual subshell
|
||||||
|
|
||||||
echo 'echo "$@"' > $tmp/dot.sh
|
TEST title='script dotted in virtual subshell'
|
||||||
before=$(getmem)
|
echo 'echo "$@"' > $tmp/dot.sh
|
||||||
for ((i=0; i < N; i++))
|
DO
|
||||||
do (. "$tmp/dot.sh" dot one two three >/dev/null)
|
(. "$tmp/dot.sh" dot one two three >/dev/null)
|
||||||
done
|
DONE
|
||||||
after=$(getmem)
|
|
||||||
err_exit_if_leak 'script dotted in virtual subshell'
|
|
||||||
|
|
||||||
echo 'echo "$@"' > $tmp/dot.sh
|
TEST title='script sourced in virtual subshell'
|
||||||
before=$(getmem)
|
echo 'echo "$@"' > $tmp/dot.sh
|
||||||
for ((i=0; i < N; i++))
|
DO
|
||||||
do (source "$tmp/dot.sh" source four five six >/dev/null)
|
(source "$tmp/dot.sh" source four five six >/dev/null)
|
||||||
done
|
DONE
|
||||||
after=$(getmem)
|
|
||||||
err_exit_if_leak 'script sourced in virtual subshell'
|
|
||||||
|
|
||||||
# ======
|
# ======
|
||||||
# Multiple leaks when using arrays in functions (Red Hat #921455)
|
# Multiple leaks when using arrays in functions (Red Hat #921455)
|
||||||
|
@ -259,31 +249,27 @@ err_exit_if_leak 'script sourced in virtual subshell'
|
||||||
# after the patch) when run in a non-C locale.
|
# after the patch) when run in a non-C locale.
|
||||||
[[ $vmalloc == enabled ]] && saveLANG=$LANG && LANG=C # comment out to test remaining leak (1/2)
|
[[ $vmalloc == enabled ]] && saveLANG=$LANG && LANG=C # comment out to test remaining leak (1/2)
|
||||||
|
|
||||||
function _hash
|
TEST title='associative array in function'
|
||||||
{
|
function _hash
|
||||||
typeset w=([abc]=1 [def]=31534 [xyz]=42)
|
{
|
||||||
print -u2 $w 2>&-
|
typeset w=([abc]=1 [def]=31534 [xyz]=42)
|
||||||
# accessing the var will leak
|
print -u2 $w 2>&-
|
||||||
}
|
# accessing the var will leak
|
||||||
before=$(getmem)
|
}
|
||||||
for ((i=0; i < N; i++))
|
DO
|
||||||
do _hash
|
_hash
|
||||||
done
|
DONE
|
||||||
after=$(getmem)
|
|
||||||
err_exit_if_leak 'associative array in function'
|
|
||||||
|
|
||||||
function _array
|
TEST title='indexed array in function'
|
||||||
{
|
function _array
|
||||||
typeset w=(1 31534 42)
|
{
|
||||||
print -u2 $w 2>&-
|
typeset w=(1 31534 42)
|
||||||
# unset w will prevent leak
|
print -u2 $w 2>&-
|
||||||
}
|
# unset w will prevent leak
|
||||||
before=$(getmem)
|
}
|
||||||
for ((i=0; i < N; i++))
|
DO
|
||||||
do _array
|
_array
|
||||||
done
|
DONE
|
||||||
after=$(getmem)
|
|
||||||
err_exit_if_leak 'indexed array in function'
|
|
||||||
|
|
||||||
[[ $vmalloc == enabled ]] && LANG=$saveLANG # comment out to test remaining leak (2/2)
|
[[ $vmalloc == enabled ]] && LANG=$saveLANG # comment out to test remaining leak (2/2)
|
||||||
|
|
||||||
|
@ -292,175 +278,126 @@ err_exit_if_leak 'indexed array in function'
|
||||||
# Fix based on: https://src.fedoraproject.org/rpms/ksh/blob/642af4d6/f/ksh-20120801-memlik3.patch
|
# Fix based on: https://src.fedoraproject.org/rpms/ksh/blob/642af4d6/f/ksh-20120801-memlik3.patch
|
||||||
# The fix was backported from ksh 93v- beta.
|
# The fix was backported from ksh 93v- beta.
|
||||||
|
|
||||||
function myFunction
|
TEST title='typeset in function called by command substitution'
|
||||||
{
|
function myFunction
|
||||||
typeset toPrint="something"
|
{
|
||||||
echo "${toPrint}"
|
typeset toPrint="something"
|
||||||
}
|
echo "${toPrint}"
|
||||||
state=$(myFunction)
|
}
|
||||||
before=$(getmem)
|
DO
|
||||||
for ((i=0; i < N; i++))
|
state=$(myFunction)
|
||||||
do state=$(myFunction)
|
DONE
|
||||||
done
|
|
||||||
after=$(getmem)
|
|
||||||
err_exit_if_leak 'typeset in function called by command substitution'
|
|
||||||
|
|
||||||
# ======
|
# ======
|
||||||
# Check that unsetting an alias frees both the node and its value
|
# Check that unsetting an alias frees both the node and its value
|
||||||
|
|
||||||
before=$(getmem)
|
TEST title='unalias'
|
||||||
for ((i=0; i < N; i++))
|
DO
|
||||||
do alias "test$i=command$i"
|
alias "test$i=command$i"
|
||||||
unalias "test$i"
|
unalias "test$i"
|
||||||
done
|
DONE
|
||||||
after=$(getmem)
|
|
||||||
err_exit_if_leak 'unalias'
|
|
||||||
|
|
||||||
# ======
|
# ======
|
||||||
# Red Hat bug rhbz#982142: command substitution leaks
|
# Red Hat bug rhbz#982142: command substitution leaks
|
||||||
|
|
||||||
# case1: Nested command substitutions
|
# case1: Nested command substitutions
|
||||||
# (reportedly already fixed in 93u+, but let's keep the test)
|
# (reportedly already fixed in 93u+, but let's keep the test)
|
||||||
before=$(getmem)
|
TEST title='nested command substitutions'
|
||||||
for ((i=0; i < N; i++))
|
DO
|
||||||
do a=`true 1 + \`true 1 + 1\`` # was: a=`expr 1 + \`expr 1 + 1\``
|
a=`true 1 + \`true 1 + 1\`` # was: a=`expr 1 + \`expr 1 + 1\``
|
||||||
done
|
DONE
|
||||||
after=$(getmem)
|
|
||||||
err_exit_if_leak 'nested command substitutions'
|
|
||||||
|
|
||||||
# case2: Command alias
|
# case2: Command alias
|
||||||
alias ls='true -ltr' # was: alias ls='ls -ltr'
|
TEST title='alias in command substitution'
|
||||||
before=$(getmem)
|
alias ls='true -ltr' # was: alias ls='ls -ltr'
|
||||||
for ((i=0; i < N; i++))
|
DO
|
||||||
do eval 'a=`ls`'
|
eval 'a=`ls`'
|
||||||
done
|
DONE
|
||||||
after=$(getmem)
|
|
||||||
unalias ls
|
|
||||||
err_exit_if_leak 'alias in command substitution'
|
|
||||||
|
|
||||||
# case3: Function call via autoload
|
# case3: Function call via autoload
|
||||||
cat >$tmp/func1 <<\EOF
|
TEST title='function call via autoload in command substitution'
|
||||||
function func1
|
cat >$tmp/func1 <<-\EOF
|
||||||
{
|
function func1
|
||||||
echo "func1 call";
|
{
|
||||||
}
|
echo "func1 call";
|
||||||
EOF
|
}
|
||||||
FPATH=$tmp
|
EOF
|
||||||
autoload func1
|
FPATH=$tmp
|
||||||
a=`func1` # steady memory state
|
autoload func1
|
||||||
before=$(getmem)
|
DO
|
||||||
for ((i=0; i < N; i++))
|
a=`func1`
|
||||||
do a=`func1`
|
DONE
|
||||||
done
|
|
||||||
after=$(getmem)
|
|
||||||
unset -f func1
|
|
||||||
unset -v FPATH
|
|
||||||
err_exit_if_leak 'function call via autoload in command substitution'
|
|
||||||
|
|
||||||
# ======
|
# ======
|
||||||
|
|
||||||
# add some random utilities to the hash table to detect memory leak on hash table reset when changing PATH
|
# add some random utilities to the hash table to detect memory leak on hash table reset when changing PATH
|
||||||
random_utils=(chmod cp mv awk sed diff comm cut sort uniq date env find mkdir rmdir pr sleep)
|
random_utils=(chmod cp mv awk sed diff comm cut sort uniq date env find mkdir rmdir pr sleep)
|
||||||
|
|
||||||
save_PATH=$PATH
|
save_PATH=$PATH
|
||||||
hash "${random_utils[@]}"
|
|
||||||
before=$(getmem)
|
|
||||||
for ((i=0; i < N; i++))
|
|
||||||
do hash -r
|
|
||||||
hash "${random_utils[@]}"
|
|
||||||
done
|
|
||||||
after=$(getmem)
|
|
||||||
err_exit_if_leak 'clear hash table (hash -r) in main shell'
|
|
||||||
|
|
||||||
before=$(getmem)
|
TEST title='clear hash table (hash -r) in main shell'
|
||||||
for ((i=0; i < N; i++))
|
DO
|
||||||
do PATH=/dev/null
|
hash -r
|
||||||
|
hash "${random_utils[@]}"
|
||||||
|
DONE
|
||||||
|
|
||||||
|
TEST title='set PATH value in main shell'
|
||||||
|
DO
|
||||||
|
PATH=/dev/null
|
||||||
PATH=$save_PATH
|
PATH=$save_PATH
|
||||||
hash "${random_utils[@]}"
|
hash "${random_utils[@]}"
|
||||||
done
|
DONE
|
||||||
after=$(getmem)
|
|
||||||
err_exit_if_leak 'set PATH value in main shell'
|
|
||||||
|
|
||||||
before=$(getmem)
|
TEST title='run command with preceding PATH assignment in main shell'
|
||||||
for ((i=0; i < N; i++))
|
DO
|
||||||
do PATH=/dev/null command true
|
PATH=/dev/null command true
|
||||||
done
|
DONE
|
||||||
after=$(getmem)
|
|
||||||
err_exit_if_leak 'run command with preceding PATH assignment in main shell'
|
|
||||||
|
|
||||||
: <<'disabled' # TODO: known leak (approx 73552 bytes after 512 iterations)
|
TEST title='set PATH attribute in main shell' known=y url=https://github.com/ksh93/ksh/issues/405
|
||||||
before=$(getmem)
|
DO
|
||||||
for ((i=0; i < N; i++))
|
typeset -A PATH
|
||||||
do typeset -A PATH
|
|
||||||
unset PATH
|
unset PATH
|
||||||
PATH=$save_PATH
|
PATH=$save_PATH
|
||||||
hash "${random_utils[@]}"
|
hash "${random_utils[@]}"
|
||||||
done
|
DONE
|
||||||
after=$(getmem)
|
|
||||||
err_exit_if_leak 'set PATH attribute in main shell'
|
|
||||||
disabled
|
|
||||||
|
|
||||||
: <<'disabled' # TODO: known leak (approx 99568 bytes after 512 iterations)
|
TEST title='unset PATH in main shell' known=y url=https://github.com/ksh93/ksh/issues/405
|
||||||
before=$(getmem)
|
DO
|
||||||
for ((i=0; i < N; i++))
|
unset PATH
|
||||||
do unset PATH
|
|
||||||
PATH=$save_PATH
|
PATH=$save_PATH
|
||||||
hash "${random_utils[@]}"
|
hash "${random_utils[@]}"
|
||||||
done
|
DONE
|
||||||
after=$(getmem)
|
|
||||||
err_exit_if_leak 'unset PATH in main shell'
|
|
||||||
disabled
|
|
||||||
|
|
||||||
hash "${random_utils[@]}"
|
TEST title='clear hash table (hash -r) in subshell'
|
||||||
before=$(getmem)
|
hash "${random_utils[@]}"
|
||||||
for ((i=0; i < N; i++))
|
DO
|
||||||
do (hash -r)
|
(hash -r)
|
||||||
done
|
DONE
|
||||||
after=$(getmem)
|
|
||||||
err_exit_if_leak 'clear hash table (hash -r) in subshell'
|
|
||||||
|
|
||||||
: <<'disabled' # TODO: known leak (approx 123520 bytes after 512 iterations)
|
TEST title='set PATH value in subshell' known=y url=https://github.com/ksh93/ksh/issues/405
|
||||||
before=$(getmem)
|
DO
|
||||||
for ((i=0; i < N; i++))
|
(PATH=/dev/null)
|
||||||
do (PATH=/dev/null)
|
DONE
|
||||||
done
|
|
||||||
after=$(getmem)
|
|
||||||
err_exit_if_leak 'set PATH value in subshell'
|
|
||||||
disabled
|
|
||||||
|
|
||||||
: <<'disabled' # TODO: known leak (approx 24544 bytes after 512 iterations)
|
TEST title='run command with preceding PATH assignment in subshell' known=y url=https://github.com/ksh93/ksh/issues/405
|
||||||
before=$(getmem)
|
DO
|
||||||
for ((i=0; i < N; i++))
|
(PATH=/dev/null command true)
|
||||||
do (PATH=/dev/null command true)
|
DONE
|
||||||
done
|
|
||||||
after=$(getmem)
|
|
||||||
err_exit_if_leak 'run command with preceding PATH assignment in subshell'
|
|
||||||
disabled
|
|
||||||
|
|
||||||
: <<'disabled' # TODO: known leak (approx 131200 bytes after 512 iterations)
|
TEST title='set PATH attribute in subshell' known=y url=https://github.com/ksh93/ksh/issues/405
|
||||||
before=$(getmem)
|
DO
|
||||||
for ((i=0; i < N; i++))
|
(readonly PATH)
|
||||||
do (readonly PATH)
|
DONE
|
||||||
done
|
|
||||||
after=$(getmem)
|
|
||||||
err_exit_if_leak 'set PATH attribute in subshell'
|
|
||||||
disabled
|
|
||||||
|
|
||||||
: <<'disabled' # TODO: known leak (approx 229440 bytes after 512 iterations)
|
TEST title='unset PATH in subshell' known=y url=https://github.com/ksh93/ksh/issues/405
|
||||||
before=$(getmem)
|
DO
|
||||||
for ((i=0; i < N; i++))
|
(unset PATH)
|
||||||
do (unset PATH)
|
DONE
|
||||||
done
|
|
||||||
after=$(getmem)
|
|
||||||
err_exit_if_leak 'unset PATH in subshell'
|
|
||||||
disabled
|
|
||||||
|
|
||||||
# ======
|
# ======
|
||||||
# Test for a memory leak after 'cd' (in relation to $PWD and $OLDPWD)
|
# Test for a memory leak after 'cd' (in relation to $PWD and $OLDPWD)
|
||||||
original_pwd=$PWD
|
TEST title='PWD and/or OLDPWD changed by cd'
|
||||||
before=$(getmem)
|
DO
|
||||||
for ((i=0; i < N; i++))
|
cd /tmp
|
||||||
do cd /tmp
|
|
||||||
cd - > /dev/null
|
cd - > /dev/null
|
||||||
PWD=/foo
|
PWD=/foo
|
||||||
OLDPWD=/bar
|
OLDPWD=/bar
|
||||||
|
@ -471,23 +408,14 @@ do cd /tmp
|
||||||
cd - > /dev/null
|
cd - > /dev/null
|
||||||
unset OLDPWD PWD
|
unset OLDPWD PWD
|
||||||
cd /bin
|
cd /bin
|
||||||
cd /tmp
|
cd "$tmp"
|
||||||
done
|
DONE
|
||||||
after=$(getmem)
|
|
||||||
err_exit_if_leak 'PWD and/or OLDPWD changed by cd'
|
|
||||||
cd $original_pwd
|
|
||||||
|
|
||||||
# ======
|
# ======
|
||||||
# https://github.com/ksh93/ksh/issues/253#issuecomment-815308466
|
TEST title='variable with discipline function in subshell' known=y url=https://github.com/ksh93/ksh/issues/404
|
||||||
: <<'disabled' # TODO: known leak(s) (approx 1008 KiB after 16384 iterations)
|
DO
|
||||||
before=$(getmem)
|
|
||||||
for ((i=0; i < N; i++))
|
|
||||||
do
|
|
||||||
(SECONDS=1; LANG=C)
|
(SECONDS=1; LANG=C)
|
||||||
done
|
DONE
|
||||||
after=$(getmem)
|
|
||||||
err_exit_if_leak 'Variable with discipline function in subshell causes memory leak'
|
|
||||||
disabled
|
|
||||||
|
|
||||||
# ======
|
# ======
|
||||||
exit $((Errors<125?Errors:125))
|
exit $((Errors<125?Errors:125))
|
||||||
|
|
|
@ -27,8 +27,6 @@
|
||||||
# read the pty manual by running: arch/*/bin/pty --man
|
# read the pty manual by running: arch/*/bin/pty --man
|
||||||
#
|
#
|
||||||
# Do not globally set the locale; these tests must pass for all locales.
|
# Do not globally set the locale; these tests must pass for all locales.
|
||||||
#
|
|
||||||
# The # err_exit # comments are to enable shtests to count the tests.
|
|
||||||
|
|
||||||
# the trickiest part of the tests is avoiding typeahead
|
# the trickiest part of the tests is avoiding typeahead
|
||||||
# in the pty dialogue
|
# in the pty dialogue
|
||||||
|
@ -101,7 +99,6 @@ then warning "pty command hangs on $bintrue -- tests skipped"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# err_exit #
|
|
||||||
tst $LINENO <<"!"
|
tst $LINENO <<"!"
|
||||||
L POSIX sh 026(C)
|
L POSIX sh 026(C)
|
||||||
|
|
||||||
|
@ -125,7 +122,6 @@ w wait
|
||||||
u (Killed|Done)
|
u (Killed|Done)
|
||||||
!
|
!
|
||||||
|
|
||||||
# err_exit #
|
|
||||||
tst $LINENO <<"!"
|
tst $LINENO <<"!"
|
||||||
L POSIX sh 028(C)
|
L POSIX sh 028(C)
|
||||||
|
|
||||||
|
@ -148,7 +144,6 @@ w wait
|
||||||
u (Killed|Done)
|
u (Killed|Done)
|
||||||
!
|
!
|
||||||
|
|
||||||
# err_exit #
|
|
||||||
tst $LINENO <<"!"
|
tst $LINENO <<"!"
|
||||||
L POSIX sh 029(C)
|
L POSIX sh 029(C)
|
||||||
|
|
||||||
|
@ -171,7 +166,6 @@ w wait
|
||||||
u (Killed|Done)
|
u (Killed|Done)
|
||||||
!
|
!
|
||||||
|
|
||||||
# err_exit #
|
|
||||||
tst $LINENO <<"!"
|
tst $LINENO <<"!"
|
||||||
L POSIX sh 091(C)
|
L POSIX sh 091(C)
|
||||||
|
|
||||||
|
@ -188,7 +182,6 @@ w o
|
||||||
u ^hello\r?\n$
|
u ^hello\r?\n$
|
||||||
!
|
!
|
||||||
|
|
||||||
# err_exit #
|
|
||||||
((SHOPT_VSH)) && tst $LINENO <<"!"
|
((SHOPT_VSH)) && tst $LINENO <<"!"
|
||||||
L POSIX sh 093(C)
|
L POSIX sh 093(C)
|
||||||
|
|
||||||
|
@ -204,7 +197,6 @@ w e
|
||||||
u ^goodbye\r?\n$
|
u ^goodbye\r?\n$
|
||||||
!
|
!
|
||||||
|
|
||||||
# err_exit #
|
|
||||||
((SHOPT_VSH)) && tst $LINENO <<"!"
|
((SHOPT_VSH)) && tst $LINENO <<"!"
|
||||||
L POSIX sh 094(C)
|
L POSIX sh 094(C)
|
||||||
|
|
||||||
|
@ -221,7 +213,6 @@ u ^hello\r?\n$
|
||||||
if [[ $(id -u) == 0 ]]
|
if [[ $(id -u) == 0 ]]
|
||||||
then warning "running as root: skipping test POSIX sh 096(C)"
|
then warning "running as root: skipping test POSIX sh 096(C)"
|
||||||
else
|
else
|
||||||
# err_exit #
|
|
||||||
tst $LINENO <<"!"
|
tst $LINENO <<"!"
|
||||||
L POSIX sh 096(C)
|
L POSIX sh 096(C)
|
||||||
|
|
||||||
|
@ -251,7 +242,6 @@ r history
|
||||||
!
|
!
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# err_exit #
|
|
||||||
tst $LINENO <<"!"
|
tst $LINENO <<"!"
|
||||||
L POSIX sh 097(C)
|
L POSIX sh 097(C)
|
||||||
|
|
||||||
|
@ -267,7 +257,6 @@ u ^ok\r?\n$
|
||||||
if [[ $(id -u) == 0 ]]
|
if [[ $(id -u) == 0 ]]
|
||||||
then warning "running as root: skipping test POSIX sh 099(C)"
|
then warning "running as root: skipping test POSIX sh 099(C)"
|
||||||
else
|
else
|
||||||
# err_exit #
|
|
||||||
tst $LINENO <<"!"
|
tst $LINENO <<"!"
|
||||||
L POSIX sh 099(C)
|
L POSIX sh 099(C)
|
||||||
|
|
||||||
|
@ -297,7 +286,6 @@ r history
|
||||||
!
|
!
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# err_exit #
|
|
||||||
tst $LINENO <<"!"
|
tst $LINENO <<"!"
|
||||||
L POSIX sh 100(C)
|
L POSIX sh 100(C)
|
||||||
|
|
||||||
|
@ -313,7 +301,6 @@ w echo ok
|
||||||
u ^ok\r?\n$
|
u ^ok\r?\n$
|
||||||
!
|
!
|
||||||
|
|
||||||
# err_exit #
|
|
||||||
((SHOPT_VSH || SHOPT_ESH)) && tst $LINENO <<"!"
|
((SHOPT_VSH || SHOPT_ESH)) && tst $LINENO <<"!"
|
||||||
L POSIX sh 101(C)
|
L POSIX sh 101(C)
|
||||||
|
|
||||||
|
@ -358,7 +345,6 @@ w echo interrupt=:\cV\cC:
|
||||||
u ^interrupt=:\cC:\r?\n$
|
u ^interrupt=:\cC:\r?\n$
|
||||||
!
|
!
|
||||||
|
|
||||||
# err_exit #
|
|
||||||
tst $LINENO <<"!"
|
tst $LINENO <<"!"
|
||||||
L POSIX sh 104(C)
|
L POSIX sh 104(C)
|
||||||
|
|
||||||
|
@ -378,7 +364,6 @@ u ^done\r?\n$
|
||||||
if [[ $(id -u) == 0 ]]
|
if [[ $(id -u) == 0 ]]
|
||||||
then warning "running as root: skipping test POSIX sh 111(C)"
|
then warning "running as root: skipping test POSIX sh 111(C)"
|
||||||
else
|
else
|
||||||
# err_exit #
|
|
||||||
((SHOPT_VSH)) && tst $LINENO <<"!"
|
((SHOPT_VSH)) && tst $LINENO <<"!"
|
||||||
L POSIX sh 111(C)
|
L POSIX sh 111(C)
|
||||||
|
|
||||||
|
@ -402,7 +387,6 @@ fi
|
||||||
if [[ $(id -u) == 0 ]]
|
if [[ $(id -u) == 0 ]]
|
||||||
then warning "running as root: skipping test POSIX sh 251(C)"
|
then warning "running as root: skipping test POSIX sh 251(C)"
|
||||||
else
|
else
|
||||||
# err_exit #
|
|
||||||
((SHOPT_VSH)) && tst $LINENO <<"!"
|
((SHOPT_VSH)) && tst $LINENO <<"!"
|
||||||
L POSIX sh 251(C)
|
L POSIX sh 251(C)
|
||||||
|
|
||||||
|
@ -461,7 +445,6 @@ u yes-yes
|
||||||
!
|
!
|
||||||
disabled
|
disabled
|
||||||
|
|
||||||
# err_exit #
|
|
||||||
# Test file name completion in vi mode
|
# Test file name completion in vi mode
|
||||||
if((SHOPT_VSH)); then
|
if((SHOPT_VSH)); then
|
||||||
mkdir "/tmp/fakehome_$$" && tst $LINENO <<!
|
mkdir "/tmp/fakehome_$$" && tst $LINENO <<!
|
||||||
|
@ -478,7 +461,6 @@ u ^/tmp/fakehome_$$/testfile_$$\r?\n$
|
||||||
rm -r "/tmp/fakehome_$$"
|
rm -r "/tmp/fakehome_$$"
|
||||||
fi # SHOPT_VSH
|
fi # SHOPT_VSH
|
||||||
|
|
||||||
# err_exit #
|
|
||||||
VISUAL='' tst $LINENO <<"!"
|
VISUAL='' tst $LINENO <<"!"
|
||||||
L raw Bourne mode literal tab characters
|
L raw Bourne mode literal tab characters
|
||||||
|
|
||||||
|
@ -494,7 +476,6 @@ r ^:test-1: true (/de\tv/nu\tl\tl|/de v/nu l l)\r\n$
|
||||||
p :test-2:
|
p :test-2:
|
||||||
!
|
!
|
||||||
|
|
||||||
# err_exit #
|
|
||||||
VISUAL='' tst $LINENO <<"!"
|
VISUAL='' tst $LINENO <<"!"
|
||||||
L raw Bourne mode backslash handling
|
L raw Bourne mode backslash handling
|
||||||
|
|
||||||
|
@ -511,8 +492,6 @@ w true incorrect\\\cXtrue correct
|
||||||
r ^:test-3: true correct\r\n$
|
r ^:test-3: true correct\r\n$
|
||||||
!
|
!
|
||||||
|
|
||||||
# err_exit #
|
|
||||||
# err_exit #
|
|
||||||
set --
|
set --
|
||||||
((SHOPT_VSH)) && set -- "$@" vi
|
((SHOPT_VSH)) && set -- "$@" vi
|
||||||
((SHOPT_ESH)) && set -- "$@" emacs gmacs
|
((SHOPT_ESH)) && set -- "$@" emacs gmacs
|
||||||
|
@ -532,7 +511,6 @@ r ^:test-2: true string\\r\\n$
|
||||||
!
|
!
|
||||||
done
|
done
|
||||||
|
|
||||||
# err_exit #
|
|
||||||
tst $LINENO <<"!"
|
tst $LINENO <<"!"
|
||||||
L notify job state changes
|
L notify job state changes
|
||||||
|
|
||||||
|
@ -543,7 +521,6 @@ w set -b; sleep .01 &
|
||||||
u Done
|
u Done
|
||||||
!
|
!
|
||||||
|
|
||||||
# err_exit #
|
|
||||||
# Tests for 'test -t'. These were moved here from bracket.sh because they require a tty.
|
# Tests for 'test -t'. These were moved here from bracket.sh because they require a tty.
|
||||||
cat >test_t.sh <<"EOF"
|
cat >test_t.sh <<"EOF"
|
||||||
integer n
|
integer n
|
||||||
|
@ -604,7 +581,6 @@ r ^OK11\r\n$
|
||||||
r ^:test-2:
|
r ^:test-2:
|
||||||
!
|
!
|
||||||
|
|
||||||
# err_exit #
|
|
||||||
tst $LINENO <<"!"
|
tst $LINENO <<"!"
|
||||||
L race condition while launching external commands
|
L race condition while launching external commands
|
||||||
|
|
||||||
|
@ -623,7 +599,6 @@ r ^/dev/null\r\n$
|
||||||
r ^:test-2:
|
r ^:test-2:
|
||||||
!
|
!
|
||||||
|
|
||||||
# err_exit #
|
|
||||||
((SHOPT_ESH)) && [[ -o ?backslashctrl ]] && tst $LINENO <<"!"
|
((SHOPT_ESH)) && [[ -o ?backslashctrl ]] && tst $LINENO <<"!"
|
||||||
L nobackslashctrl in emacs
|
L nobackslashctrl in emacs
|
||||||
|
|
||||||
|
@ -637,7 +612,6 @@ w \cR\\\cH\cH
|
||||||
r ^:test-2: \r\n$
|
r ^:test-2: \r\n$
|
||||||
!
|
!
|
||||||
|
|
||||||
# err_exit #
|
|
||||||
((SHOPT_ESH)) && tst $LINENO <<"!"
|
((SHOPT_ESH)) && tst $LINENO <<"!"
|
||||||
L emacs backslash escaping
|
L emacs backslash escaping
|
||||||
|
|
||||||
|
@ -655,7 +629,6 @@ w true \\\cC
|
||||||
r true \^C
|
r true \^C
|
||||||
!
|
!
|
||||||
|
|
||||||
# err_exit #
|
|
||||||
((SHOPT_VSH)) && touch vi_completion_A_file vi_completion_B_file && tst $LINENO <<"!"
|
((SHOPT_VSH)) && touch vi_completion_A_file vi_completion_B_file && tst $LINENO <<"!"
|
||||||
L vi filename completion menu
|
L vi filename completion menu
|
||||||
|
|
||||||
|
@ -690,7 +663,6 @@ r ^:test-3: ls vi_completion_A_file\r\n$
|
||||||
r ^vi_completion_A_file\r\n$
|
r ^vi_completion_A_file\r\n$
|
||||||
!
|
!
|
||||||
|
|
||||||
# err_exit #
|
|
||||||
tst $LINENO <<"!"
|
tst $LINENO <<"!"
|
||||||
L syntax error added to history file
|
L syntax error added to history file
|
||||||
|
|
||||||
|
@ -706,7 +678,6 @@ r ^:test-2: fc -lN1\r\n$
|
||||||
r \tdo something\r\n$
|
r \tdo something\r\n$
|
||||||
!
|
!
|
||||||
|
|
||||||
# err_exit #
|
|
||||||
tst $LINENO <<"!"
|
tst $LINENO <<"!"
|
||||||
L value of $? after the shell uses a variable with a discipline function
|
L value of $? after the shell uses a variable with a discipline function
|
||||||
|
|
||||||
|
@ -730,7 +701,6 @@ w echo "Exit status is: $?"
|
||||||
u Exit status is: 1
|
u Exit status is: 1
|
||||||
!
|
!
|
||||||
|
|
||||||
# err_exit #
|
|
||||||
((SHOPT_ESH)) && ((SHOPT_VSH)) && tst $LINENO <<"!"
|
((SHOPT_ESH)) && ((SHOPT_VSH)) && tst $LINENO <<"!"
|
||||||
L crash after switching from emacs to vi mode
|
L crash after switching from emacs to vi mode
|
||||||
|
|
||||||
|
@ -751,7 +721,6 @@ r ^:test-2: echo Success\r\n$
|
||||||
r ^Success\r\n$
|
r ^Success\r\n$
|
||||||
!
|
!
|
||||||
|
|
||||||
# err_exit #
|
|
||||||
((SHOPT_VSH || SHOPT_ESH)) && tst $LINENO <<"!"
|
((SHOPT_VSH || SHOPT_ESH)) && tst $LINENO <<"!"
|
||||||
L value of $? after tilde expansion in tab completion
|
L value of $? after tilde expansion in tab completion
|
||||||
|
|
||||||
|
@ -769,7 +738,6 @@ w echo $? ~\t
|
||||||
u 42 /tmp
|
u 42 /tmp
|
||||||
!
|
!
|
||||||
|
|
||||||
# err_exit #
|
|
||||||
((SHOPT_MULTIBYTE && (SHOPT_VSH || SHOPT_ESH))) &&
|
((SHOPT_MULTIBYTE && (SHOPT_VSH || SHOPT_ESH))) &&
|
||||||
[[ ${LC_ALL:-${LC_CTYPE:-${LANG:-}}} =~ [Uu][Tt][Ff]-?8 ]] &&
|
[[ ${LC_ALL:-${LC_CTYPE:-${LANG:-}}} =~ [Uu][Tt][Ff]-?8 ]] &&
|
||||||
touch $'XXX\xc3\xa1' $'XXX\xc3\xab' &&
|
touch $'XXX\xc3\xa1' $'XXX\xc3\xab' &&
|
||||||
|
@ -783,7 +751,6 @@ w : XX\t
|
||||||
r ^:test-1: : XXX\r\n$
|
r ^:test-1: : XXX\r\n$
|
||||||
!
|
!
|
||||||
|
|
||||||
# err_exit #
|
|
||||||
((SHOPT_VSH)) && tst $LINENO <<"!"
|
((SHOPT_VSH)) && tst $LINENO <<"!"
|
||||||
L Using b, B, w and W commands in vi mode
|
L Using b, B, w and W commands in vi mode
|
||||||
# https://github.com/att/ast/issues/1467
|
# https://github.com/att/ast/issues/1467
|
||||||
|
@ -797,7 +764,6 @@ r ^:test-2: echo asdf\r\n$
|
||||||
r ^asdf\r\n$
|
r ^asdf\r\n$
|
||||||
!
|
!
|
||||||
|
|
||||||
# err_exit #
|
|
||||||
((SHOPT_ESH)) && mkdir -p emacstest/123abc && VISUAL=emacs tst $LINENO <<"!"
|
((SHOPT_ESH)) && mkdir -p emacstest/123abc && VISUAL=emacs tst $LINENO <<"!"
|
||||||
L autocomplete stops numeric input
|
L autocomplete stops numeric input
|
||||||
# https://github.com/ksh93/ksh/issues/198
|
# https://github.com/ksh93/ksh/issues/198
|
||||||
|
@ -808,7 +774,6 @@ w cd emacste\t123abc
|
||||||
r ^:test-1: cd emacstest/123abc\r\n$
|
r ^:test-1: cd emacstest/123abc\r\n$
|
||||||
!
|
!
|
||||||
|
|
||||||
# err_exit #
|
|
||||||
echo '((' >$tmp/synerror
|
echo '((' >$tmp/synerror
|
||||||
ENV=$tmp/synerror tst $LINENO <<"!"
|
ENV=$tmp/synerror tst $LINENO <<"!"
|
||||||
L syntax error in profile causes exit on startup
|
L syntax error in profile causes exit on startup
|
||||||
|
@ -822,7 +787,6 @@ r ^:test-1: echo ok\r\n$
|
||||||
r ^ok\r\n$
|
r ^ok\r\n$
|
||||||
!
|
!
|
||||||
|
|
||||||
# err_exit #
|
|
||||||
((SHOPT_VSH)) && tst $LINENO <<"!"
|
((SHOPT_VSH)) && tst $LINENO <<"!"
|
||||||
L split on quoted whitespace when extracting words from command history
|
L split on quoted whitespace when extracting words from command history
|
||||||
# https://github.com/ksh93/ksh/pull/291
|
# https://github.com/ksh93/ksh/pull/291
|
||||||
|
@ -836,7 +800,6 @@ w :\E_
|
||||||
r ^:test-2: : One\\ "Two Three"\$'Four Five'\.mp3\r\n$
|
r ^:test-2: : One\\ "Two Three"\$'Four Five'\.mp3\r\n$
|
||||||
!
|
!
|
||||||
|
|
||||||
# err_exit #
|
|
||||||
((SHOPT_VSH)) && tst $LINENO <<"!"
|
((SHOPT_VSH)) && tst $LINENO <<"!"
|
||||||
L crash when entering comment into history file (vi mode)
|
L crash when entering comment into history file (vi mode)
|
||||||
# https://github.com/att/ast/issues/798
|
# https://github.com/att/ast/issues/798
|
||||||
|
@ -851,7 +814,6 @@ r \t#foo\r\n$
|
||||||
r \thist -lnN 1\r\n$
|
r \thist -lnN 1\r\n$
|
||||||
!
|
!
|
||||||
|
|
||||||
# err_exit #
|
|
||||||
((SHOPT_VSH || SHOPT_ESH)) && tst $LINENO <<"!"
|
((SHOPT_VSH || SHOPT_ESH)) && tst $LINENO <<"!"
|
||||||
L tab completion while expanding ${.sh.*} variables
|
L tab completion while expanding ${.sh.*} variables
|
||||||
# https://github.com/att/ast/issues/1461
|
# https://github.com/att/ast/issues/1461
|
||||||
|
@ -862,7 +824,6 @@ w test \$\{.sh.level\t
|
||||||
r ^:test-1: test \$\{.sh.level\}\r\n$
|
r ^:test-1: test \$\{.sh.level\}\r\n$
|
||||||
!
|
!
|
||||||
|
|
||||||
# err_exit #
|
|
||||||
((SHOPT_VSH || SHOPT_ESH)) && tst $LINENO <<"!"
|
((SHOPT_VSH || SHOPT_ESH)) && tst $LINENO <<"!"
|
||||||
L tab completion executes command substitutions
|
L tab completion executes command substitutions
|
||||||
# https://github.com/ksh93/ksh/issues/268
|
# https://github.com/ksh93/ksh/issues/268
|
||||||
|
@ -876,7 +837,6 @@ w `echo true`\t
|
||||||
r ^:test-2: `echo true`\r\n$
|
r ^:test-2: `echo true`\r\n$
|
||||||
!
|
!
|
||||||
|
|
||||||
# err_exit #
|
|
||||||
((SHOPT_ESH)) && VISUAL=emacs tst $LINENO <<"!"
|
((SHOPT_ESH)) && VISUAL=emacs tst $LINENO <<"!"
|
||||||
L emacs: keys with repeat parameters repeat extra steps
|
L emacs: keys with repeat parameters repeat extra steps
|
||||||
# https://github.com/ksh93/ksh/issues/292
|
# https://github.com/ksh93/ksh/issues/292
|
||||||
|
@ -896,7 +856,6 @@ w : test_string\1\E6\E[C\4
|
||||||
r ^:test-4: : teststring\r\n$
|
r ^:test-4: : teststring\r\n$
|
||||||
!
|
!
|
||||||
|
|
||||||
# err_exit #
|
|
||||||
tst $LINENO <<"!"
|
tst $LINENO <<"!"
|
||||||
L crash with KEYBD trap after entering multi-line command substitution
|
L crash with KEYBD trap after entering multi-line command substitution
|
||||||
# https://www.mail-archive.com/ast-users@lists.research.att.com/msg00313.html
|
# https://www.mail-archive.com/ast-users@lists.research.att.com/msg00313.html
|
||||||
|
@ -907,7 +866,6 @@ w true); echo "Exit status is $?"
|
||||||
u Exit status is 0
|
u Exit status is 0
|
||||||
!
|
!
|
||||||
|
|
||||||
# err_exit #
|
|
||||||
tst $LINENO <<"!"
|
tst $LINENO <<"!"
|
||||||
L interrupted PS2 discipline function
|
L interrupted PS2 discipline function
|
||||||
# https://github.com/ksh93/ksh/issues/347
|
# https://github.com/ksh93/ksh/issues/347
|
||||||
|
@ -929,7 +887,6 @@ r > \)
|
||||||
r one two three end
|
r one two three end
|
||||||
!
|
!
|
||||||
|
|
||||||
# err_exit #
|
|
||||||
((SHOPT_VSH || SHOPT_ESH)) && tst $LINENO <<"!"
|
((SHOPT_VSH || SHOPT_ESH)) && tst $LINENO <<"!"
|
||||||
L tab completion of '.' and '..'
|
L tab completion of '.' and '..'
|
||||||
# https://github.com/ksh93/ksh/issues/372
|
# https://github.com/ksh93/ksh/issues/372
|
||||||
|
@ -948,7 +905,6 @@ w : ..\t
|
||||||
r : \.\./\r\n$
|
r : \.\./\r\n$
|
||||||
!
|
!
|
||||||
|
|
||||||
# err_exit #
|
|
||||||
tst $LINENO <<"!"
|
tst $LINENO <<"!"
|
||||||
L Ctrl+C with SIGINT ignored
|
L Ctrl+C with SIGINT ignored
|
||||||
# https://github.com/ksh93/ksh/issues/343
|
# https://github.com/ksh93/ksh/issues/343
|
||||||
|
|
|
@ -8,7 +8,7 @@ valgrindflags='--xml=yes --log-file=/dev/null --track-origins=yes --read-var-inf
|
||||||
|
|
||||||
USAGE=$'
|
USAGE=$'
|
||||||
[-s8?
|
[-s8?
|
||||||
@(#)$Id: shtests (ksh 93u+m) 2021-12-20 $
|
@(#)$Id: shtests (ksh 93u+m) 2021-12-28 $
|
||||||
]
|
]
|
||||||
[-author?David Korn <dgk@research.att.com>]
|
[-author?David Korn <dgk@research.att.com>]
|
||||||
[-author?Glenn Fowler <gsf@research.att.com>]
|
[-author?Glenn Fowler <gsf@research.att.com>]
|
||||||
|
@ -344,6 +344,8 @@ do [[ $i == *.sh ]] || i+='.sh'
|
||||||
fi
|
fi
|
||||||
t=$( case $i in
|
t=$( case $i in
|
||||||
glob.sh) grep -c '^[[:blank:]]*test_[a-z]\{3,\}' $i ;;
|
glob.sh) grep -c '^[[:blank:]]*test_[a-z]\{3,\}' $i ;;
|
||||||
|
leaks.sh) grep -c ^TEST $i ;;
|
||||||
|
pty.sh) grep -c 'tst ' $i ;;
|
||||||
*) grep -c err_exit $i ;;
|
*) grep -c err_exit $i ;;
|
||||||
esac )
|
esac )
|
||||||
tests[$i]=$t
|
tests[$i]=$t
|
||||||
|
|
|
@ -100,6 +100,10 @@ while whence $TEST_notfound >/dev/null 2>&1
|
||||||
do TEST_notfound=notfound-$RANDOM
|
do TEST_notfound=notfound-$RANDOM
|
||||||
done
|
done
|
||||||
|
|
||||||
|
for exp in 65535 65536
|
||||||
|
do got=$($SHELL -c 'x=$(printf "%.*c" '$exp' x); print ${#x}' 2>&1)
|
||||||
|
[[ $got == $exp ]] || err_exit "large command substitution failed -- expected $exp, got $got"
|
||||||
|
done
|
||||||
|
|
||||||
integer BS=1024 nb=64 ss=60 bs no
|
integer BS=1024 nb=64 ss=60 bs no
|
||||||
for bs in $BS 1
|
for bs in $BS 1
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue