import CS ksh-1.0.6-3.el9

This commit is contained in:
eabdullin 2024-03-28 10:40:15 +00:00
parent a0481fcde2
commit e5c95b5de9
9 changed files with 897 additions and 536 deletions

2
.gitignore vendored
View File

@ -1 +1 @@
SOURCES/ksh-1.0.0-beta.1.tar.gz
SOURCES/ksh-1.0.6.tar.gz

View File

@ -1 +1 @@
b22e526c9db91f9cab97af78f51b33b045a5c1e5 SOURCES/ksh-1.0.0-beta.1.tar.gz
9d3e1fb4406fa31a888a3599e1cfb54713df1e03 SOURCES/ksh-1.0.6.tar.gz

View File

@ -1,365 +0,0 @@
From 541dd6f286a71c0d1d874807e61551026d03f409 Mon Sep 17 00:00:00 2001
From: Vincent Mihalkovic <vmihalko@redhat.com>
Date: Tue, 3 Aug 2021 10:20:04 +0200
Subject: [PATCH] src/cmd/ksh93/tests: (temporary) disable failing tests
---
src/cmd/ksh93/tests/functions.sh | 2 ++
src/cmd/ksh93/tests/io.sh | 2 ++
src/cmd/ksh93/tests/leaks.sh | 49 ++++++++++++++++++++++++++++++--
src/cmd/ksh93/tests/tilde.sh | 4 +--
src/cmd/ksh93/tests/variables.sh | 2 ++
5 files changed, 54 insertions(+), 5 deletions(-)
diff --git a/src/cmd/ksh93/tests/functions.sh b/src/cmd/ksh93/tests/functions.sh
index 731c1a6..43bb32a 100755
--- a/src/cmd/ksh93/tests/functions.sh
+++ b/src/cmd/ksh93/tests/functions.sh
@@ -146,10 +146,12 @@ fi
if [[ $PWD != "$dir" ]]
then err_exit 'cd inside nested subshell changes $PWD'
fi
+: <<'disabled' # TODO: failing only on i686 arch
fun() "$bin_echo" hello
if [[ $(fun) != hello ]]
then err_exit one line functions not working
fi
+disabled
cat > $tmp/script <<-\!
print -r -- "$1"
!
diff --git a/src/cmd/ksh93/tests/io.sh b/src/cmd/ksh93/tests/io.sh
index 2752145..f94c801 100755
--- a/src/cmd/ksh93/tests/io.sh
+++ b/src/cmd/ksh93/tests/io.sh
@@ -241,7 +241,9 @@ then [[ $(3<#) -eq 0 ]] || err_exit "not at position 0"
read -u3 && err_exit "not found pattern not positioning at eof"
cat $tmp/seek | read -r <# *WWW*
[[ $REPLY == *WWWWW* ]] || err_exit '<# not working for pipes'
+: <<'disabled' # TODO: failing only on armv7, i686 arch. Reason: https://github.com/att/ast/commit/a5c692e1bd0d800e3f19be249d3170e69cbe001d
{ < $tmp/seek <# ((2358336120)) ;} 2> /dev/null || err_exit 'long seek not working'
+disabled
else err_exit "$tmp/seek: cannot open for reading"
fi
redirect 3<&- || 'cannot close 3'
diff --git a/src/cmd/ksh93/tests/leaks.sh b/src/cmd/ksh93/tests/leaks.sh
index 0f50da2..6c8acfd 100755
--- a/src/cmd/ksh93/tests/leaks.sh
+++ b/src/cmd/ksh93/tests/leaks.sh
@@ -109,6 +109,7 @@ 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
+: <<'disabled' # TODO: upstream, leak sometimes on some archs
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"
for ((i=0; i < 8; i++)) # steady state first
@@ -122,8 +123,10 @@ done | while read -u$n -C stat
done {n}<&0-
after=$(getmem)
err_exit_if_leak "memory leak with read -C when deleting compound variable"
+disabled
# extra 'read's to get to steady state
+: <<'disabled' # TODO: upstream, leak sometimes on some archs
for ((i=0; i < 10; i++))
do read -C stat <<< "$data"
done
@@ -133,10 +136,12 @@ do read -C stat <<< "$data"
done
after=$(getmem)
err_exit_if_leak "memory leak with read -C when using <<<"
+disabled
# ======
# Unsetting an associative array shouldn't cause a memory leak
# See https://www.mail-archive.com/ast-users@lists.research.att.com/msg01016.html
+: <<'disabled' # TODO: upstream, leak sometimes on some archs
typeset -A stuff
before=$(getmem)
for (( i=0; i < N; i++ ))
@@ -152,6 +157,7 @@ done
unset stuff
after=$(getmem)
err_exit_if_leak 'unset of associative array causes memory leak'
+disabled
# ======
# Memory leak when resetting PATH and clearing hash table
@@ -167,17 +173,20 @@ 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:
+: <<'disabled' # TODO: upstream, leak sometimes on some archs
before=$(getmem)
for ((i=0; i < N; i++))
do PATH=/dev/null true # set/restore PATH & clear hash table
done >/dev/null
after=$(getmem)
err_exit_if_leak 'memory leak on PATH reset'
+disabled
# ======
# Defining a function in a virtual subshell
# https://github.com/ksh93/ksh/issues/114
+: <<'disabled' # TODO: upstream, leak sometimes on some archs
unset -f foo
before=$(getmem)
for ((i=0; i < N; i++))
@@ -186,7 +195,9 @@ 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'
+disabled
+: <<'disabled' # TODO: upstream, leak sometimes on some archs
unset -f foo
before=$(getmem)
for ((i=0; i < N; i++))
@@ -195,9 +206,10 @@ 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'
+disabled
# Unsetting a function in a virtual subshell
-
+: <<'disabled' # TODO: upstream, leak sometimes on some archs
function foo { echo bar; }
before=$(getmem)
for ((i=0; i < N; i++))
@@ -206,8 +218,11 @@ 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'
+disabled
+: <<'disabled' # TODO: upstream, leak sometimes on some archs
foo() { echo bar; }
+
before=$(getmem)
for ((i=0; i < N; i++))
do (unset -f foo)
@@ -215,24 +230,29 @@ 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'
+disabled
+: <<'disabled' # TODO: upstream, leak sometimes on some archs
before=$(getmem)
for ((i=0; i < N; i++))
do (function foo { echo baz; }; unset -f foo)
done
after=$(getmem)
err_exit_if_leak 'ksh function defined and unset in virtual subshell'
+disabled
+: <<'disabled' # TODO: upstream, leak sometimes on some archs
before=$(getmem)
for ((i=0; i < N; i++))
do (foo() { echo baz; }; unset -f foo)
done
after=$(getmem)
err_exit_if_leak 'POSIX function defined and unset in virtual subshell'
+disabled
# ======
# Sourcing a dot script in a virtual subshell
-
+: <<'disabled' # TODO: upstream, leak sometimes on some archs
echo 'echo "$@"' > $tmp/dot.sh
before=$(getmem)
for ((i=0; i < N; i++))
@@ -240,6 +260,7 @@ do (. "$tmp/dot.sh" dot one two three >/dev/null)
done
after=$(getmem)
err_exit_if_leak 'script dotted in virtual subshell'
+disabled
echo 'echo "$@"' > $tmp/dot.sh
before=$(getmem)
@@ -253,6 +274,8 @@ err_exit_if_leak 'script sourced in virtual subshell'
# Multiple leaks when using arrays in functions (Red Hat #921455)
# Fix based on: https://src.fedoraproject.org/rpms/ksh/blob/642af4d6/f/ksh-20120801-memlik.patch
+: <<'disabled' # TODO: upstream, leak sometimes on some archs
+
# TODO: both of these tests still leak (although much less after the patch) when run in a non-C locale.
saveLANG=$LANG; LANG=C # comment out to test remaining leak (1/2)
@@ -268,7 +291,9 @@ do _hash
done
after=$(getmem)
err_exit_if_leak 'associative array in function'
+disabled
+: <<'disabled' # TODO: upstream, leak sometimes on some archs
function _array
{
typeset w=(1 31534 42)
@@ -283,12 +308,13 @@ after=$(getmem)
err_exit_if_leak 'indexed array in function'
LANG=$saveLANG # comment out to test remaining leak (2/2)
+disabled
# ======
# Memory leak in typeset (Red Hat #1036470)
# Fix based on: https://src.fedoraproject.org/rpms/ksh/blob/642af4d6/f/ksh-20120801-memlik3.patch
# The fix was backported from ksh 93v- beta.
-
+: <<'disabled' # TODO: upstream, leak sometimes on some archs
function myFunction
{
typeset toPrint="something"
@@ -301,10 +327,12 @@ do state=$(myFunction)
done
after=$(getmem)
err_exit_if_leak 'typeset in function called by command substitution'
+disabled
# ======
# Check that unsetting an alias frees both the node and its value
+: <<'disabled' # TODO: upstream, leak sometimes on some archs
before=$(getmem)
for ((i=0; i < N; i++))
do alias "test$i=command$i"
@@ -312,10 +340,12 @@ do alias "test$i=command$i"
done
after=$(getmem)
err_exit_if_leak 'unalias'
+disabled
# ======
# Red Hat bug rhbz#982142: command substitution leaks
+: <<'disabled' # TODO: upstream, leak sometimes on some archs
# case1: Nested command substitutions
# (reportedly already fixed in 93u+, but let's keep the test)
before=$(getmem)
@@ -324,8 +354,10 @@ do a=`true 1 + \`true 1 + 1\`` # was: a=`expr 1 + \`expr 1 + 1\``
done
after=$(getmem)
err_exit_if_leak 'nested command substitutions'
+disabled
# case2: Command alias
+: <<'disabled' # TODO: upstream, leak sometimes on some archs
alias ls='true -ltr' # was: alias ls='ls -ltr'
before=$(getmem)
for ((i=0; i < N; i++))
@@ -334,8 +366,10 @@ done
after=$(getmem)
unalias ls
err_exit_if_leak 'alias in command substitution'
+disabled
# case3: Function call via autoload
+: <<'disabled' # TODO: upstream, leak sometimes on some archs
cat >$tmp/func1 <<\EOF
function func1
{
@@ -353,12 +387,14 @@ after=$(getmem)
unset -f func1
unset -v FPATH
err_exit_if_leak 'function call via autoload in command substitution'
+disabled
# ======
# 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)
+: <<'disabled' # TODO: upstream, leak sometimes on some archs
save_PATH=$PATH
hash "${random_utils[@]}"
before=$(getmem)
@@ -368,7 +404,9 @@ do hash -r
done
after=$(getmem)
err_exit_if_leak 'clear hash table (hash -r) in main shell'
+disabled
+: <<'disabled' # TODO: upstream, leak sometimes on some archs
before=$(getmem)
for ((i=0; i < N; i++))
do PATH=/dev/null
@@ -377,13 +415,16 @@ do PATH=/dev/null
done
after=$(getmem)
err_exit_if_leak 'set PATH value in main shell'
+disabled
+: <<'disabled' # TODO: upstream, leak sometimes on some archs
before=$(getmem)
for ((i=0; i < N; i++))
do PATH=/dev/null command true
done
after=$(getmem)
err_exit_if_leak 'run command with preceding PATH assignment in main shell'
+disabled
: <<'disabled' # TODO: known leak (approx 73552 bytes after 512 iterations)
before=$(getmem)
@@ -454,6 +495,7 @@ disabled
# ======
# Test for a memory leak after 'cd' (in relation to $PWD and $OLDPWD)
+: <<'disabled' # TODO: upstream, leak sometimes on some archs
original_pwd=$PWD
before=$(getmem)
for ((i=0; i < N; i++))
@@ -473,6 +515,7 @@ done
after=$(getmem)
err_exit_if_leak 'PWD and/or OLDPWD changed by cd'
cd $original_pwd
+disabled
# ======
# https://github.com/ksh93/ksh/issues/253#issuecomment-815308466
diff --git a/src/cmd/ksh93/tests/tilde.sh b/src/cmd/ksh93/tests/tilde.sh
index 1be00b9..1de0b16 100755
--- a/src/cmd/ksh93/tests/tilde.sh
+++ b/src/cmd/ksh93/tests/tilde.sh
@@ -151,13 +151,13 @@ do (
[[ $got == "$exp" ]] || err_exit "$disc discipline: counter:" \
"expected $(printf %q "$exp"), got $(printf %q "$got")"
((i==5)) || err_exit "$disc discipline: counter: $i != 5"
-
+: << 'disabled' # TODO sometimes fails on armv7 arch
set -- ~spc ~spc ~spc
got=$#,$1,$2,$3
exp=$'3,one\ttwo three\n\tfour,one\ttwo three\n\tfour,one\ttwo three\n\tfour'
[[ $got == "$exp" ]] || err_exit "$disc discipline: quoting of whitespace:" \
"expected $(printf %q "$exp"), got $(printf %q "$got")"
-
+disabled
print "$Errors" >$tmp/Errors
) &
wait "$!" 2>crashmsg
diff --git a/src/cmd/ksh93/tests/variables.sh b/src/cmd/ksh93/tests/variables.sh
index 253f84a..8b306a1 100755
--- a/src/cmd/ksh93/tests/variables.sh
+++ b/src/cmd/ksh93/tests/variables.sh
@@ -58,6 +58,7 @@ rand2=$($SHELL -c 'RANDOM=1; (echo $RANDOM)')
(( rand1 == rand2 )) && err_exit "Test 3: \$RANDOM seed in subshell doesn't change" \
"(both results are $rand1)"
# $RANDOM should be reseeded for the ( simple_command & ) optimization
+: <<'disabled' # Reason: On slower systems it could fail with an arithmetic syntax error because the output was verified before it had been written. From: https://github.com/ksh93/ksh/commit/33269cae615c913592e776276b480bf1d722ff07
( echo $RANDOM & ) >r1
( echo $RANDOM & ) >r2
integer giveup=0
@@ -74,6 +75,7 @@ fi
kill $! 2>/dev/null
trap - USR1
unset giveup
+disabled
# Virtual subshells should not influence the parent shell's RANDOM sequence
RANDOM=456
exp="$RANDOM $RANDOM $RANDOM $RANDOM $RANDOM"
--
2.31.1

View File

@ -1,151 +0,0 @@
diff --git a/src/cmd/ksh93/bltins/cd_pwd.c b/src/cmd/ksh93/bltins/cd_pwd.c
index e441805..715171c 100644
--- a/src/cmd/ksh93/bltins/cd_pwd.c
+++ b/src/cmd/ksh93/bltins/cd_pwd.c
@@ -91,8 +91,6 @@ int b_cd(int argc, char *argv[],Shbltin_t *context)
oldpwd = path_pwd(shp,0);
opwdnod = sh_scoped(shp,OLDPWDNOD);
pwdnod = sh_scoped(shp,PWDNOD);
- if(oldpwd == e_dot && pwdnod->nvalue.cp)
- oldpwd = (char*)pwdnod->nvalue.cp; /* if path_pwd() failed to get the pwd, use $PWD */
if(shp->subshell)
{
opwdnod = sh_assignok(opwdnod,1);
@@ -116,7 +114,7 @@ int b_cd(int argc, char *argv[],Shbltin_t *context)
if(shp->subshell && !shp->subshare)
{
#if _lib_fchdir
- if(!test_inode(nv_getval(pwdnod),e_dot))
+ if(!test_inode(shp->pwd,e_dot))
#endif
sh_subfork();
}
@@ -221,6 +219,7 @@ success:
if(*dp && (*dp!='.'||dp[1]) && strchr(dir,'/'))
sfputr(sfstdout,dir,'\n');
nv_putval(opwdnod,oldpwd,NV_RDONLY);
+ free((void*)shp->pwd);
if(*dir == '/')
{
flag = strlen(dir);
@@ -229,16 +228,12 @@ success:
dir[flag] = 0;
nv_putval(pwdnod,dir,NV_RDONLY);
nv_onattr(pwdnod,NV_EXPORT);
- if(shp->pwd)
- free((void*)shp->pwd);
- shp->pwd = sh_strdup(pwdnod->nvalue.cp);
+ shp->pwd = sh_strdup(dir);
}
else
{
/* pathcanon() failed to canonicalize the directory, which happens when 'cd' is invoked from a
nonexistent PWD with a relative path as the argument. Reinitialize $PWD as it will be wrong. */
- if(shp->pwd)
- free((void*)shp->pwd);
shp->pwd = NIL(const char*);
path_pwd(shp,0);
if(*shp->pwd != '/')
@@ -279,7 +274,7 @@ int b_pwd(int argc, char *argv[],Shbltin_t *context)
errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
UNREACHABLE();
}
- if(*(cp = path_pwd(shp,0)) != '/')
+ if(*(cp = path_pwd(shp,0)) != '/' || !test_inode(cp,e_dot))
{
errormsg(SH_DICT,ERROR_system(1), e_pwd);
UNREACHABLE();
diff --git a/src/cmd/ksh93/data/msg.c b/src/cmd/ksh93/data/msg.c
index 5cec66d..ee44e81 100644
--- a/src/cmd/ksh93/data/msg.c
+++ b/src/cmd/ksh93/data/msg.c
@@ -82,7 +82,7 @@ const char e_badpattern[] = "%s: invalid shell pattern";
const char e_noread[] = "%s: pattern seek requires read access";
const char e_logout[] = "Use 'exit' to terminate this shell";
const char e_exec[] = "%s: cannot execute";
-const char e_pwd[] = "cannot access parent directories";
+const char e_pwd[] = "determine present working directory";
const char e_found[] = "%s: not found";
#ifdef ENAMETOOLONG
const char e_toolong[] = "%s: file name too long";
diff --git a/src/cmd/ksh93/sh/path.c b/src/cmd/ksh93/sh/path.c
index eb18d8c..c097b5f 100644
--- a/src/cmd/ksh93/sh/path.c
+++ b/src/cmd/ksh93/sh/path.c
@@ -249,7 +249,12 @@ char *path_pwd(Shell_t *shp,int flag)
NOT_USED(flag);
/* Don't bother if PWD already set */
if(shp->pwd)
- return((char*)shp->pwd);
+ {
+ if(*shp->pwd=='/')
+ return((char*)shp->pwd);
+ free((void*)shp->pwd);
+
+ }
/* First see if PWD variable is correct */
pwdnod = sh_scoped(shp,PWDNOD);
cp = nv_getval(pwdnod);
@@ -261,22 +266,29 @@ char *path_pwd(Shell_t *shp,int flag)
cp = nv_getval(sh_scoped(shp,HOME));
if(!(cp && *cp=='/' && test_inode(cp,e_dot)))
{
- /* Get physical PWD (no symlinks) using getcwd(3), fall back to "." */
+ /* Get physical PWD (no symlinks) using getcwd(3) */
cp = getcwd(NIL(char*),0);
- if(!cp)
- return((char*)e_dot);
- tofree++;
+ if(cp)
+ tofree++;
}
/* Store in PWD variable */
- if(shp->subshell)
- pwdnod = sh_assignok(pwdnod,1);
- nv_putval(pwdnod,cp,NV_RDONLY);
+ if(cp)
+ {
+ if(shp->subshell)
+ pwdnod = sh_assignok(pwdnod,1);
+ nv_putval(pwdnod,cp,NV_RDONLY);
+ }
if(tofree)
- free(cp);
+ free((void*)cp);
}
nv_onattr(pwdnod,NV_EXPORT);
+ /* Neither obtained the pwd nor can fall back to sane-ish $PWD: fall back to "." */
+ if(!cp)
+ cp = nv_getval(pwdnod);
+ if(!cp || *cp!='/')
+ nv_putval(pwdnod,cp=(char*)e_dot,NV_RDONLY);
/* Set shell PWD */
- shp->pwd = sh_strdup(pwdnod->nvalue.cp);
+ shp->pwd = sh_strdup(cp);
return((char*)shp->pwd);
}
diff --git a/src/cmd/ksh93/tests/path.sh b/src/cmd/ksh93/tests/path.sh
index 4b2a97d..2da7d1f 100755
--- a/src/cmd/ksh93/tests/path.sh
+++ b/src/cmd/ksh93/tests/path.sh
@@ -902,5 +902,19 @@ got=$?
[[ $exp == $got ]] || err_exit "Test 7E: exit status or error message for exec'd command with long name wrong" \
"(expected $exp, got $got)"
+# ======
+# Crash after unsetting PWD
+(unset PWD; (cd /); :) & # the : avoids optimizing out the subshell
+wait "$!" 2>/dev/null
+((!(e = $?))) || err_exit "shell crashes on 'cd' in subshell exit with unset PWD" \
+ "(got status $e$( ((e>128)) && print -n /SIG && kill -l "$e"))"
+mkdir "$tmp/testdir"
+cd "$tmp/testdir"
+"$SHELL" -c 'cd /; rmdir "$1"' x "$tmp/testdir"
+(unset PWD; exec "$SHELL" -c '(cd /); :') &
+wait "$!" 2>/dev/null
+((!(e = $?))) || err_exit 'shell crashes on failure obtain the PWD on init' \
+ "(got status $e$( ((e>128)) && print -n /SIG && kill -l "$e"))"
+
# ======
exit $((Errors<125?Errors:125))

View File

@ -0,0 +1,541 @@
diff --git a/src/cmd/ksh93/Mamfile b/src/cmd/ksh93/Mamfile
index f6e6ac8..9d72d87 100644
--- a/src/cmd/ksh93/Mamfile
+++ b/src/cmd/ksh93/Mamfile
@@ -220,30 +220,18 @@ make install
done pmain.o generated
make libshell.a archive
prev shell.req
- make cd_pwd.o
- make bltins/cd_pwd.c
- make include/test.h implicit
- prev include/shtable.h implicit
- make include/defs.h implicit
- prev include/regress.h implicit dontcare
- prev include/shtable.h
- prev include/shell.h
- prev ${PACKAGE_ast_INCLUDE}/endian.h
- prev include/name.h
- prev include/argnod.h implicit
- prev ${PACKAGE_ast_INCLUDE}/cdt.h
- prev ${PACKAGE_ast_INCLUDE}/error.h
- prev ${PACKAGE_ast_INCLUDE}/sfio.h
+ make alarm.o
+ make bltins/alarm.c
+ make FEATURE/time implicit
+ prev features/time
+ exec - iffe ${IFFEFLAGS} -v -c "${CC} ${mam_cc_FLAGS} ${CCFLAGS} ${LDFLAGS}" ref ${mam_cc_L+-L.} ${mam_cc_L+-L${INSTALLROOT}/lib} -I${PACKAGE_ast_INCLUDE} -I${INSTALLROOT}/include ${mam_libdll} ${mam_libcmd} ${mam_libast} ${mam_libm} ${mam_libnsl} : run features/time
+ make ${PACKAGE_ast_INCLUDE}/times.h implicit
+ prev ${PACKAGE_ast_INCLUDE}/ast_time.h implicit
prev ${PACKAGE_ast_INCLUDE}/ast.h
- done include/defs.h
- done include/test.h
- make ${PACKAGE_ast_INCLUDE}/ls.h implicit
- prev ${PACKAGE_ast_INCLUDE}/ast_mode.h implicit dontcare
- prev ${PACKAGE_ast_INCLUDE}/ast_fs.h
- prev ${PACKAGE_ast_INCLUDE}/ast_std.h
- done ${PACKAGE_ast_INCLUDE}/ls.h
+ done ${PACKAGE_ast_INCLUDE}/times.h
+ done FEATURE/time generated
make include/builtins.h implicit
- prev include/shtable.h
+ prev include/shtable.h implicit
make FEATURE/dynamic implicit
prev features/dynamic
exec - iffe ${IFFEFLAGS} -v -c "${CC} ${mam_cc_FLAGS} ${CCFLAGS} ${LDFLAGS}" ref ${mam_cc_L+-L.} ${mam_cc_L+-L${INSTALLROOT}/lib} -I${PACKAGE_ast_INCLUDE} -I${INSTALLROOT}/include ${mam_libdll} ${mam_libcmd} ${mam_libast} ${mam_libm} ${mam_libnsl} : run features/dynamic
@@ -251,6 +239,36 @@ make install
done FEATURE/dynamic generated
prev ${PACKAGE_ast_INCLUDE}/option.h
done include/builtins.h
+ prev ${PACKAGE_ast_INCLUDE}/error.h
+ make include/defs.h implicit
+ prev include/regress.h implicit
+ prev include/shtable.h
+ prev include/shell.h
+ prev ${PACKAGE_ast_INCLUDE}/endian.h
+ prev include/name.h
+ prev include/argnod.h implicit
+ prev ${PACKAGE_ast_INCLUDE}/cdt.h
+ prev FEATURE/externs
+ prev ${PACKAGE_ast_INCLUDE}/error.h
+ prev ${PACKAGE_ast_INCLUDE}/sfio.h
+ prev ${PACKAGE_ast_INCLUDE}/ast.h
+ done include/defs.h
+ prev shopt.h
+ done bltins/alarm.c
+ exec - ${CC} ${mam_cc_FLAGS} ${CCFLAGS} -I. -Iinclude -I${PACKAGE_ast_INCLUDE} -D_API_ast=20100309 -DERROR_CONTEXT_T=Error_context_t -c bltins/alarm.c
+ done alarm.o generated
+ make cd_pwd.o
+ make bltins/cd_pwd.c
+ make include/test.h implicit
+ prev include/shtable.h
+ prev include/defs.h
+ done include/test.h
+ make ${PACKAGE_ast_INCLUDE}/ls.h implicit
+ prev ${PACKAGE_ast_INCLUDE}/ast_mode.h implicit
+ prev ${PACKAGE_ast_INCLUDE}/ast_fs.h
+ prev ${PACKAGE_ast_INCLUDE}/ast_std.h
+ done ${PACKAGE_ast_INCLUDE}/ls.h
+ prev include/builtins.h
prev include/name.h
make include/path.h implicit
make FEATURE/acct implicit
@@ -341,14 +359,7 @@ make install
make misc.o
make bltins/misc.c
prev ${PACKAGE_ast_INCLUDE}/times.h
- make FEATURE/time implicit
- prev features/time
- exec - iffe ${IFFEFLAGS} -v -c "${CC} ${mam_cc_FLAGS} ${CCFLAGS} ${LDFLAGS}" ref ${mam_cc_L+-L.} ${mam_cc_L+-L${INSTALLROOT}/lib} -I${PACKAGE_ast_INCLUDE} -I${INSTALLROOT}/include ${mam_libdll} ${mam_libcmd} ${mam_libast} ${mam_libm} ${mam_libnsl} : run features/time
- make ${PACKAGE_ast_INCLUDE}/times.h implicit
- prev ${PACKAGE_ast_INCLUDE}/ast_time.h implicit dontcare
- prev ${PACKAGE_ast_INCLUDE}/ast.h
- done ${PACKAGE_ast_INCLUDE}/times.h dontcare
- done FEATURE/time generated
+ prev FEATURE/time
prev FEATURE/locale
make include/jobs.h implicit
prev ${PACKAGE_ast_INCLUDE}/vmalloc.h
@@ -1175,7 +1186,7 @@ make install
done edit/hexpand.c
exec - ${CC} ${mam_cc_FLAGS} ${CCFLAGS} -I. -Iinclude -I${PACKAGE_ast_INCLUDE} -D_API_ast=20100309 -DERROR_CONTEXT_T=Error_context_t -c edit/hexpand.c
done hexpand.o generated
- exec - ${AR} rc libshell.a cd_pwd.o cflow.o enum.o getopts.o hist.o misc.o mkservice.o print.o read.o sleep.o trap.o test.o typeset.o ulimit.o umask.o whence.o main.o nvdisc.o nvtype.o arith.o args.o array.o completion.o defs.o edit.o expand.o regress.o fault.o fcin.o
+ exec - ${AR} rc libshell.a alarm.o cd_pwd.o cflow.o enum.o getopts.o hist.o misc.o mkservice.o print.o read.o sleep.o trap.o test.o typeset.o ulimit.o umask.o whence.o main.o nvdisc.o nvtype.o arith.o args.o array.o completion.o defs.o edit.o expand.o regress.o fault.o fcin.o
exec - ${AR} rc libshell.a history.o init.o io.o jobs.o lex.o macro.o name.o nvtree.o parse.o path.o string.o streval.o subshell.o tdump.o timers.o trestore.o waitevent.o xec.o limits.o msg.o strdata.o testops.o keywords.o options.o signals.o aliases.o builtins.o variables.o lexstates.o emacs.o vi.o hexpand.o
exec - (ranlib libshell.a) >/dev/null 2>&1 || true
done libshell.a generated
diff --git a/src/cmd/ksh93/bltins/alarm.c b/src/cmd/ksh93/bltins/alarm.c
new file mode 100644
index 0000000..f31bed7
--- /dev/null
+++ b/src/cmd/ksh93/bltins/alarm.c
@@ -0,0 +1,277 @@
+/***********************************************************************
+* *
+* This software is part of the ast package *
+* Copyright (c) 1982-2012 AT&T Intellectual Property *
+* Copyright (c) 2020-2023 Contributors to ksh 93u+m *
+* and is licensed under the *
+* Eclipse Public License, Version 2.0 *
+* *
+* A copy of the License is available at *
+* https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html *
+* (with md5 checksum 84283fa8859daf213bdda5a9f8d1be1d) *
+* *
+* David Korn <dgk@research.att.com> *
+* Martijn Dekker <martijn@inlv.org> *
+* Johnothan King <johnothanking@protonmail.com> *
+* *
+***********************************************************************/
+/*
+ * alarm [-r] [varname [+]when]
+ *
+ * David Korn
+ * AT&T Labs
+ *
+ */
+
+/*
+ * TODO: 2014 email from David Korn cited at <https://bugzilla.redhat.com/1176670>:
+ *
+ * > I never documented the alarm builtin because it is problematic. The
+ * > problem is that traps can't safely be handled asynchronously. What should
+ * > happen is that the trap is marked for execution (sh.trapnote) and run after
+ * > the current command completes. The time trap should wake up the shell if
+ * > it is blocked and it should return and then handle the trap.
+ */
+
+#include "shopt.h"
+#include "defs.h"
+#include <error.h>
+#include "builtins.h"
+#include "FEATURE/time"
+
+#define R_FLAG 1
+#define L_FLAG 2
+
+struct tevent
+{
+ Namfun_t fun;
+ Namval_t *node;
+ Namval_t *action;
+ struct tevent *next;
+ long milli;
+ int flags;
+ void *timeout;
+};
+
+static const char ALARM[] = "alarm";
+
+static void trap_timeout(void*);
+
+/*
+ * insert timeout item on current given list in sorted order
+ */
+static void *time_add(struct tevent *item, void *list)
+{
+ struct tevent *tp = (struct tevent*)list;
+ if(!tp || item->milli < tp->milli)
+ {
+ item->next = tp;
+ list = item;
+ }
+ else
+ {
+ while(tp->next && item->milli > tp->next->milli)
+ tp = tp->next;
+ item->next = tp->next;
+ tp->next = item;
+ }
+ tp = item;
+ tp->timeout = sh_timeradd(tp->milli,tp->flags&R_FLAG,trap_timeout,tp);
+ return list;
+}
+
+/*
+ * delete timeout item from current given list, delete timer
+ */
+static void *time_delete(struct tevent *item, void *list)
+{
+ struct tevent *tp = (struct tevent*)list;
+ if(item==tp)
+ list = tp->next;
+ else
+ {
+ while(tp && tp->next != item)
+ tp = tp->next;
+ if(tp)
+ tp->next = item->next;
+ }
+ if(item->timeout)
+ sh_timerdel(item->timeout);
+ return list;
+}
+
+static void print_alarms(void *list)
+{
+ struct tevent *tp = (struct tevent*)list;
+ while(tp)
+ {
+ if(tp->timeout)
+ {
+ char *name = nv_name(tp->node);
+ if(tp->flags&R_FLAG)
+ {
+ double d = tp->milli;
+ sfprintf(sfstdout,e_alrm1,name,d/1000.);
+ }
+ else
+ sfprintf(sfstdout,e_alrm2,name,nv_getnum(tp->node));
+ }
+ tp = tp->next;
+ }
+}
+
+static void trap_timeout(void* handle)
+{
+ struct tevent *tp = (struct tevent*)handle;
+ sh.trapnote |= SH_SIGALRM;
+ if(!(tp->flags&R_FLAG))
+ tp->timeout = 0;
+ tp->flags |= L_FLAG;
+ sh.sigflag[SIGALRM] |= SH_SIGALRM;
+ if(sh_isstate(SH_TTYWAIT))
+ sh_timetraps();
+}
+
+void sh_timetraps(void)
+{
+ struct tevent *tp, *tpnext;
+ struct tevent *tptop;
+ while(1)
+ {
+ sh.sigflag[SIGALRM] &= ~SH_SIGALRM;
+ tptop= (struct tevent*)sh.st.timetrap;
+ for(tp=tptop;tp;tp=tpnext)
+ {
+ tpnext = tp->next;
+ if(tp->flags&L_FLAG)
+ {
+ tp->flags &= ~L_FLAG;
+ if(tp->action)
+ sh_fun(tp->action,tp->node,NULL);
+ tp->flags &= ~L_FLAG;
+ if(!tp->flags)
+ nv_unset(tp->node);
+ }
+ }
+ if(!(sh.sigflag[SIGALRM]&SH_SIGALRM))
+ break;
+ }
+}
+
+
+/*
+ * This trap function catches "alarm" actions only
+ */
+static char *setdisc(Namval_t *np, const char *event, Namval_t* action, Namfun_t *fp)
+{
+ struct tevent *tp = (struct tevent*)fp;
+ if(!event)
+ return action ? Empty : (char*)ALARM;
+ if(strcmp(event,ALARM)!=0)
+ {
+ /* try the next level */
+ return nv_setdisc(np, event, action, fp);
+ }
+ if(action==np)
+ action = tp->action;
+ else
+ tp->action = action;
+ return action ? (char*)action : Empty;
+}
+
+/*
+ * catch assignments and set alarm traps
+ */
+static void putval(Namval_t* np, const char* val, int flag, Namfun_t* fp)
+{
+ struct tevent *tp = (struct tevent*)fp;
+ double d;
+ if(val)
+ {
+ double now;
+#ifdef timeofday
+ struct timeval tmp;
+ timeofday(&tmp);
+ now = tmp.tv_sec + 1.e-6*tmp.tv_usec;
+#else
+ now = (double)time(NULL);
+#endif /* timeofday */
+ nv_putv(np,val,flag,fp);
+ d = nv_getnum(np);
+ if(*val=='+')
+ {
+ double x = d + now;
+ nv_putv(np,(char*)&x,NV_INTEGER|NV_DOUBLE,fp);
+ }
+ else
+ d -= now;
+ tp->milli = 1000*(d+.0005);
+ if(tp->timeout)
+ sh.st.timetrap = time_delete(tp,sh.st.timetrap);
+ if(tp->milli > 0)
+ sh.st.timetrap = time_add(tp,sh.st.timetrap);
+ }
+ else
+ {
+ tp = (struct tevent*)nv_stack(np, NULL);
+ sh.st.timetrap = time_delete(tp,sh.st.timetrap);
+ nv_unset(np);
+ free(fp);
+ }
+}
+
+static const Namdisc_t alarmdisc =
+{
+ sizeof(struct tevent),
+ putval,
+ 0,
+ 0,
+ setdisc,
+};
+
+int b_alarm(int argc,char *argv[],Shbltin_t *context)
+{
+ int n,rflag=0;
+ Namval_t *np;
+ struct tevent *tp;
+ while (n = optget(argv, sh_optalarm)) switch (n)
+ {
+ case 'r':
+ rflag = R_FLAG;
+ break;
+ case ':':
+ errormsg(SH_DICT,2, "%s", opt_info.arg);
+ break;
+ case '?':
+ errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg);
+ UNREACHABLE();
+ }
+ argc -= opt_info.index;
+ argv += opt_info.index;
+ if(error_info.errors)
+ {
+ errormsg(SH_DICT,ERROR_usage(2),optusage(NULL));
+ UNREACHABLE();
+ }
+ if(argc==0)
+ {
+ print_alarms(sh.st.timetrap);
+ return 0;
+ }
+ if(argc!=2)
+ {
+ errormsg(SH_DICT,ERROR_usage(2),optusage(NULL));
+ UNREACHABLE();
+ }
+ np = nv_open(argv[0],sh.var_tree,NV_NOARRAY|NV_VARNAME);
+ if(!nv_isnull(np))
+ nv_unset(np);
+ nv_setattr(np, NV_DOUBLE);
+ tp = sh_newof(NULL,struct tevent,1,0);
+ tp->fun.disc = &alarmdisc;
+ tp->flags = rflag;
+ tp->node = np;
+ nv_stack(np,(Namfun_t*)tp);
+ nv_putval(np, argv[1], 0);
+ return 0;
+}
diff --git a/src/cmd/ksh93/bltins/sleep.c b/src/cmd/ksh93/bltins/sleep.c
index b34e62d..3bb55b1 100644
--- a/src/cmd/ksh93/bltins/sleep.c
+++ b/src/cmd/ksh93/bltins/sleep.c
@@ -127,6 +127,8 @@ skip:
if(tloc < (now=time(NULL)))
break;
d = (double)(tloc-now);
+ if(sh.sigflag[SIGALRM]&SH_SIGTRAP)
+ sh_timetraps();
}
return 0;
}
diff --git a/src/cmd/ksh93/data/builtins.c b/src/cmd/ksh93/data/builtins.c
index 760b7ce..22ea156 100644
--- a/src/cmd/ksh93/data/builtins.c
+++ b/src/cmd/ksh93/data/builtins.c
@@ -116,6 +116,7 @@ const struct shtable3 shtab_builtins[] =
"pwd", NV_BLTIN|BLT_ENV, bltin(pwd),
"read", NV_BLTIN|BLT_ENV, bltin(read),
"sleep", NV_BLTIN, bltin(sleep),
+ "alarm", NV_BLTIN|BLT_ENV, bltin(alarm),
"times", NV_BLTIN|BLT_ENV|BLT_SPC, bltin(times),
"ulimit", NV_BLTIN|BLT_ENV, bltin(ulimit),
"umask", NV_BLTIN|BLT_ENV, bltin(umask),
@@ -2170,6 +2171,8 @@ const char sh_optwhence[] =
;
+const char e_alrm1[] = "alarm -r %s +%.3g\n";
+const char e_alrm2[] = "alarm %s %.3f\n";
const char e_baddisc[] = "%s: invalid discipline function";
const char e_nofork[] = "cannot fork";
const char e_nosignal[] = "%s: unknown signal name";
diff --git a/src/cmd/ksh93/include/builtins.h b/src/cmd/ksh93/include/builtins.h
index 34c697c..f6b3f59 100644
--- a/src/cmd/ksh93/include/builtins.h
+++ b/src/cmd/ksh93/include/builtins.h
@@ -115,6 +115,8 @@ extern int b_times(int, char*[],Shbltin_t*);
extern short b_enum_nelem(Namfun_t*);
+extern const char e_alrm1[];
+extern const char e_alrm2[];
extern const char e_badfun[];
extern const char e_baddisc[];
extern const char e_nofork[];
diff --git a/src/cmd/ksh93/include/defs.h b/src/cmd/ksh93/include/defs.h
index 306ea7e..b5bfb67 100644
--- a/src/cmd/ksh93/include/defs.h
+++ b/src/cmd/ksh93/include/defs.h
@@ -143,6 +143,7 @@ extern void sh_subjobcheck(pid_t);
extern int sh_subsavefd(int);
extern void sh_subtmpfile(void);
extern char *sh_substitute(const char*,const char*,char*);
+extern void sh_timetraps(void);
extern const char *_sh_translate(const char*);
extern int sh_trace(char*[],int);
extern void sh_trim(char*);
diff --git a/src/cmd/ksh93/include/fault.h b/src/cmd/ksh93/include/fault.h
index b57a0ab..7750f80 100644
--- a/src/cmd/ksh93/include/fault.h
+++ b/src/cmd/ksh93/include/fault.h
@@ -58,6 +58,7 @@ typedef void (*SH_SIGTYPE)(int,void(*)(int));
#define SH_SIGIGNORE 040 /* default is ignore signal */
#define SH_SIGINTERACTIVE 0100 /* handle interactive specially */
#define SH_SIGTSTP 0200 /* tstp signal received */
+#define SH_SIGALRM 0200 /* timer alarm received */
#define SH_SIGTERM SH_SIGOFF /* term signal received */
#define SH_SIGRUNTIME 0400 /* runtime value */
diff --git a/src/cmd/ksh93/include/shell.h b/src/cmd/ksh93/include/shell.h
index 57c402d..9794995 100644
--- a/src/cmd/ksh93/include/shell.h
+++ b/src/cmd/ksh93/include/shell.h
@@ -211,6 +211,7 @@ struct sh_scoped
char **otrap; /* save parent pseudosignals for v=$(trap) */
char **trapcom; /* EXIT and signals */
char **otrapcom; /* save parent EXIT and signals for v=$(trap) */
+ void *timetrap;
struct Ufunction *real_fun; /* current 'function name' function */
int repl_index;
char *repl_arg;
diff --git a/src/cmd/ksh93/sh/fault.c b/src/cmd/ksh93/sh/fault.c
index 3409a6c..510bf56 100644
--- a/src/cmd/ksh93/sh/fault.c
+++ b/src/cmd/ksh93/sh/fault.c
@@ -447,6 +447,8 @@ void sh_chktrap(void)
sh_exit(sh.exitval);
}
}
+ if(sh.sigflag[SIGALRM]&SH_SIGALRM)
+ sh_timetraps();
#if SHOPT_BGX
if((sh.sigflag[SIGCHLD]&SH_SIGTRAP) && sh.st.trapcom[SIGCHLD])
job_chldtrap(1);
diff --git a/src/cmd/ksh93/sh/jobs.c b/src/cmd/ksh93/sh/jobs.c
index 116ae3b..be333b2 100644
--- a/src/cmd/ksh93/sh/jobs.c
+++ b/src/cmd/ksh93/sh/jobs.c
@@ -1466,6 +1466,8 @@ int job_wait(pid_t pid)
continue;
if(nochild)
break;
+ if(sh.sigflag[SIGALRM]&SH_SIGTRAP)
+ sh_timetraps();
if((intr && sh.trapnote) || (pid==1 && !intr))
break;
}
diff --git a/src/cmd/ksh93/tests/builtins.sh b/src/cmd/ksh93/tests/builtins.sh
index 83b4086..92d2708 100755
--- a/src/cmd/ksh93/tests/builtins.sh
+++ b/src/cmd/ksh93/tests/builtins.sh
@@ -1222,6 +1222,28 @@ function test_usage
done 3< <(builtin)
}; test_usage
+# ======
+# The 'alarm' builtin could make 'read' crash due to IFS table corruption caused by unsafe asynchronous execution.
+# https://bugzilla.redhat.com/1176670
+if (builtin alarm) 2>/dev/null
+then got=$( { "$SHELL" -c '
+ builtin alarm
+ alarm -r alarm_handler +.005
+ i=0
+ function alarm_handler.alarm
+ {
+ let "(++i) > 20" && exit
+ }
+ while :; do
+ echo cargo,odds and ends,jetsam,junk,wreckage,castoffs,sea-drift
+ done | while IFS="," read arg1 arg2 arg3 arg4 junk; do
+ :
+ done
+ '; } 2>&1)
+ ((!(e = $?))) || err_exit 'crash with alarm and IFS' \
+ "(got status $e$( ((e>128)) && print -n /SIG && kill -l "$e"), $(printf %q "$got"))"
+fi
+
# ======
# Verify that the POSIX 'test' builtin exits with status 2 when given an invalid binary operator.
for operator in '===' ']]'
@@ -1581,7 +1603,7 @@ let Errors+=$?
# Most built-ins should handle --version
while IFS= read -r bltin <&3
do case $bltin in
- echo | test | true | false | \[ | : | catclose | catgets | catopen | Dt* | _Dt* | X* | login | newgrp )
+ alarm | echo | test | true | false | \[ | : | catclose | catgets | catopen | Dt* | _Dt* | X* | login | newgrp )
continue ;;
fc | hist )
((SHOPT_SCRIPTONLY)) && continue ;;

View File

@ -0,0 +1,162 @@
diff --git a/src/cmd/ksh93/Mamfile b/src/cmd/ksh93/Mamfile
index abc9ee1a5..d266f2178 100644
--- a/src/cmd/ksh93/Mamfile
+++ b/src/cmd/ksh93/Mamfile
@@ -222,6 +222,10 @@ make install
prev shell.req
make alarm.o
make bltins/alarm.c
+ make include/io.h implicit
+ prev ${PACKAGE_ast_INCLUDE}/sfio.h
+ prev ${PACKAGE_ast_INCLUDE}/ast.h
+ done include/io.h
make FEATURE/time implicit
prev features/time
exec - iffe ${IFFEFLAGS} -v -c "${CC} ${mam_cc_FLAGS} ${CCFLAGS} ${LDFLAGS}" ref ${mam_cc_L+-L.} ${mam_cc_L+-L${INSTALLROOT}/lib} -I${PACKAGE_ast_INCLUDE} -I${INSTALLROOT}/include ${mam_libdll} ${mam_libcmd} ${mam_libast} ${mam_libm} ${mam_libnsl} : run features/time
@@ -239,6 +243,22 @@ make install
done FEATURE/dynamic generated
prev ${PACKAGE_ast_INCLUDE}/option.h
done include/builtins.h
+ make include/shlex.h implicit
+ make include/lexstates.h implicit
+ prev ${PACKAGE_ast_INCLUDE}/wctype.h
+ prev ${PACKAGE_ast_INCLUDE}/wchar.h
+ make FEATURE/locale implicit
+ prev features/locale
+ exec - iffe ${IFFEFLAGS} -v -c "${CC} ${mam_cc_FLAGS} ${CCFLAGS} ${LDFLAGS}" ref ${mam_cc_L+-L.} ${mam_cc_L+-L${INSTALLROOT}/lib} -I${PACKAGE_ast_INCLUDE} -I${INSTALLROOT}/include ${mam_libdll} ${mam_libcmd} ${mam_libast} ${mam_libm} ${mam_libnsl} : run features/locale
+ done FEATURE/locale generated
+ done include/lexstates.h
+ prev include/shtable.h
+ make include/shnodes.h implicit
+ prev include/argnod.h implicit
+ prev ${PACKAGE_ast_INCLUDE}/ast.h
+ done include/shnodes.h
+ prev ${PACKAGE_ast_INCLUDE}/cdt.h
+ done include/shlex.h
prev ${PACKAGE_ast_INCLUDE}/error.h
make include/defs.h implicit
prev include/regress.h implicit
@@ -246,7 +266,7 @@ make install
prev include/shell.h
prev ${PACKAGE_ast_INCLUDE}/endian.h
prev include/name.h
- prev include/argnod.h implicit
+ prev include/argnod.h
prev ${PACKAGE_ast_INCLUDE}/cdt.h
prev FEATURE/externs
prev ${PACKAGE_ast_INCLUDE}/error.h
@@ -292,10 +312,7 @@ make install
make cflow.o
make bltins/cflow.c
prev include/builtins.h
- make include/shnodes.h implicit
- prev include/argnod.h
- prev ${PACKAGE_ast_INCLUDE}/ast.h
- done include/shnodes.h
+ prev include/shnodes.h
prev ${PACKAGE_ast_INCLUDE}/error.h
prev ${PACKAGE_ast_INCLUDE}/ast.h
prev include/defs.h
@@ -341,10 +358,7 @@ make install
done FEATURE/ttys generated
done include/terminal.h
prev ${PACKAGE_ast_INCLUDE}/sig.h
- make FEATURE/locale implicit
- prev features/locale
- exec - iffe ${IFFEFLAGS} -v -c "${CC} ${mam_cc_FLAGS} ${CCFLAGS} ${LDFLAGS}" ref ${mam_cc_L+-L.} ${mam_cc_L+-L${INSTALLROOT}/lib} -I${PACKAGE_ast_INCLUDE} -I${INSTALLROOT}/include ${mam_libdll} ${mam_libcmd} ${mam_libast} ${mam_libm} ${mam_libnsl} : run features/locale
- done FEATURE/locale generated
+ prev FEATURE/locale
make FEATURE/cmds implicit
prev features/cmds
exec - iffe ${IFFEFLAGS} -v -c "${CC} ${mam_cc_FLAGS} ${CCFLAGS} ${LDFLAGS}" ref ${mam_cc_L+-L.} ${mam_cc_L+-L${INSTALLROOT}/lib} -I${PACKAGE_ast_INCLUDE} -I${INSTALLROOT}/include ${mam_libdll} ${mam_libcmd} ${mam_libast} ${mam_libm} ${mam_libnsl} : run features/cmds
@@ -353,6 +367,7 @@ make install
prev include/builtins.h
prev include/history.h
prev include/name.h
+ prev include/io.h
make include/io.h implicit
prev ${PACKAGE_ast_INCLUDE}/sfio.h
prev ${PACKAGE_ast_INCLUDE}/ast.h
@@ -443,11 +458,7 @@ make install
prev include/builtins.h
prev include/name.h
prev include/io.h
- make include/lexstates.h implicit
- prev ${PACKAGE_ast_INCLUDE}/wctype.h
- prev ${PACKAGE_ast_INCLUDE}/wchar.h
- prev FEATURE/locale
- done include/lexstates.h
+ prev include/lexstates.h
prev include/variables.h
prev include/defs.h
prev ${PACKAGE_ast_INCLUDE}/error.h
@@ -545,12 +556,7 @@ make install
make whence.o
make bltins/whence.c
prev include/builtins.h
- make include/shlex.h implicit
- prev include/lexstates.h
- prev include/shtable.h
- prev include/shnodes.h
- prev ${PACKAGE_ast_INCLUDE}/cdt.h
- done include/shlex.h
+ prev include/shlex.h
prev include/path.h
prev include/name.h
prev include/shtable.h
diff --git a/src/cmd/ksh93/bltins/alarm.c b/src/cmd/ksh93/bltins/alarm.c
index f31bed711..63d4d6cbf 100644
--- a/src/cmd/ksh93/bltins/alarm.c
+++ b/src/cmd/ksh93/bltins/alarm.c
@@ -23,21 +23,13 @@
*
*/
-/*
- * TODO: 2014 email from David Korn cited at <https://bugzilla.redhat.com/1176670>:
- *
- * > I never documented the alarm builtin because it is problematic. The
- * > problem is that traps can't safely be handled asynchronously. What should
- * > happen is that the trap is marked for execution (sh.trapnote) and run after
- * > the current command completes. The time trap should wake up the shell if
- * > it is blocked and it should return and then handle the trap.
- */
-
#include "shopt.h"
#include "defs.h"
#include <error.h>
+#include <shlex.h>
#include "builtins.h"
#include "FEATURE/time"
+#include "io.h"
#define R_FLAG 1
#define L_FLAG 2
@@ -147,7 +139,26 @@ void sh_timetraps(void)
{
tp->flags &= ~L_FLAG;
if(tp->action)
- sh_fun(tp->action,tp->node,NULL);
+ {
+ /* Call the alarm discipline function. This may occur at any time including parse time,
+ * so save the lexer state and push/pop context to make sure we can restore it. */
+ struct checkpt checkpoint;
+ int jmpval;
+ int savexit = sh.savexit;
+ Lex_t *lexp = (Lex_t*)sh.lex_context, savelex = *lexp;
+ sh_lexopen(lexp, 0); /* needs full init (0), not what it calls reinit (1) */
+ sh_pushcontext(&checkpoint, 1);
+ jmpval = sigsetjmp(checkpoint.buff,0);
+ if(!jmpval)
+ sh_fun(tp->action,tp->node,NULL);
+ sh_popcontext(&checkpoint);
+ if(sh.topfd != checkpoint.topfd)
+ sh_iorestore(checkpoint.topfd,jmpval);
+ *lexp = savelex;
+ sh.savexit = savexit; /* avoid influencing $? */
+ if(jmpval)
+ siglongjmp(*sh.jmplist,jmpval);
+ }
tp->flags &= ~L_FLAG;
if(!tp->flags)
nv_unset(tp->node);

View File

@ -0,0 +1,99 @@
From 2075b2b96208ac8b989ca316dcdd674c3f488e2b Mon Sep 17 00:00:00 2001
From: Martijn Dekker <martijn@inlv.org>
Date: Thu, 28 Dec 2023 04:02:28 +0000
Subject: [PATCH] Fix crash on failure to trim ~/.sh_history
@vmihalko writes:
> We were able to reproduce an old issue mentioned in
> https://bugzilla.redhat.com/show_bug.cgi?id=1885399 using the
> latest version of ksh. The corresponding code has not changed
> much in the past few years.
>
> To provide further explanation, the problem arises when a user's
> .sh_history file grows to a size that triggers the hist_trim
> function, but the user lacks (after the creation of .sh_history)
> the necessary write permissions to their $HOME directory. As a
> result, ksh becomes stuck in a recursive loop between the
> sh_histinit(src/cmd/ksh93/edit/history.c#L203) function and the
> hist_trim(src/cmd/ksh93/edit/history.c#L417) function.
>
> Conditions for reproduction:
>
> 1. The size of the .sh_history file is larger than the HIST_MAX
> limit. (src/cmd/ksh93/edit/history.c, line 325)
> 2. .sh_history file has not been changed in the HIST_RECENT
> seconds (src/cmd/ksh93/edit/history.c, line 406)
> 3. The user does not have permission to write to the $HOME
> directory.
src/cmd/ksh93/edit/history.c: hist_trim():
- Print a warning and return if unlink(2) fails. The warning tells
the user to check the history file's parent directory is
writable. This is the best I realistically do for now, because
this function's basic method assumes a writable parent directory.
- The temp file fallback is deleted because it's fundamentally
flawed: it assumes the temp file is made on the same volume as
the history file and can simply be rename(2)'d in place. Even
on systems where this is the case, it doesn't appear to be
working correctly, but this is not worth looking into.
Resolves: https://github.com/ksh93/ksh/issues/695
---
src/cmd/ksh93/edit/history.c | 34 ++++------------------------------
1 files changed, 4 insertions(+), 30 deletions(-)
diff --git a/src/cmd/ksh93/edit/history.c b/src/cmd/ksh93/edit/history.c
index c49c23244d00..f3672bf6e220 100644
--- a/src/cmd/ksh93/edit/history.c
+++ b/src/cmd/ksh93/edit/history.c
@@ -419,34 +419,13 @@ static History_t* hist_trim(History_t *hp, int n)
char *cp;
int incmd=1, c=0;
History_t *hist_new, *hist_old = hp;
- char *buff, *endbuff, *tmpname=0;
+ char *buff, *endbuff;
off_t oldp,newp;
struct stat statb;
- unlink(hist_old->histname);
- if(access(hist_old->histname,F_OK) >= 0)
+ if(unlink(hist_old->histname) < 0)
{
- /* The unlink can fail on Windows 95 */
- int fd;
- char *last, *name=hist_old->histname;
- sh_close(sffileno(hist_old->histfp));
- tmpname = (char*)sh_malloc(strlen(name)+14);
- if(last = strrchr(name,'/'))
- {
- *last = 0;
- pathtmp(tmpname,name,"hist",NULL);
- *last = '/';
- }
- else
- pathtmp(tmpname,e_dot,"hist",NULL);
- if(rename(name,tmpname) < 0)
- {
- free(tmpname);
- tmpname = name;
- }
- fd = open(tmpname,O_RDONLY|O_cloexec);
- sfsetfd(hist_old->histfp,fd);
- if(tmpname==name)
- tmpname = 0;
+ errormsg(SH_DICT,ERROR_warn(0),"cannot trim history file %s; make sure parent directory is writable",hist_old->histname);
+ return hist_ptr = hist_old;
}
hist_ptr = 0;
if(fstat(sffileno(hist_old->histfp),&statb)>=0)
@@ -501,11 +480,6 @@ static History_t* hist_trim(History_t *hp, int n)
}
hist_cancel(hist_new);
sfclose(hist_old->histfp);
- if(tmpname)
- {
- unlink(tmpname);
- free(tmpname);
- }
free((char*)hist_old);
return hist_ptr = hist_new;
}

View File

@ -0,0 +1,58 @@
From 9eb8532ccacf1cfdb7ba18f51eba68776852ef7c Mon Sep 17 00:00:00 2001
From: Vincent Mihalkovic <vmihalko@redhat.com>
Date: Thu, 8 Feb 2024 22:10:58 +0100
Subject: [PATCH] Re-fix use of strdup on a NULL pointer (re: 9a9da2c2) (#718)
Thank you @lzaoral for debugging this issue and creating this
reproducer:
$ tty # check that the shell is connected to a pseudoterminal
/dev/pts/4
$ mkdir /var/tmp/chroottest
$ dnf --releasever=39 --installroot=/var/tmp/chroottest install ksh
$ echo "/dev/udp/127.0.0.1/514;0;104" |
sudo tee /var/tmp/chroottest/etc/ksh_audit
$ sudo chroot /var/tmp/chroottest /bin/ksh -lic 'exit 0'
(ksh segfaults)
Analysis: On Linux, ttyname(3)[*] may fail if:
* EBADF Bad file descriptor.
* ENODEV fd refers to a slave pseudoterminal device but the
corresponding pathname could not be found [...].
* ENOTTY fd does not refer to a terminal device.
Calling isatty(3) before ttyname(3) only prevents the first and
third cases.
src/cmd/ksh93/edit/history.c: sh_histinit():
- To catch the second case, let's call ttyname(2) directly, check
for NULL and remove the redundant isatty() call.
[*] https://man7.org/linux/man-pages/man3/ttyname.3.html
---
src/cmd/ksh93/edit/history.c | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/src/cmd/ksh93/edit/history.c b/src/cmd/ksh93/edit/history.c
index a7b084e5c16f..25832a59265b 100644
--- a/src/cmd/ksh93/edit/history.c
+++ b/src/cmd/ksh93/edit/history.c
@@ -15,6 +15,7 @@
* Johnothan King <johnothanking@protonmail.com> *
* hyenias <58673227+hyenias@users.noreply.github.com> *
* Govind Kamat <govind_kamat@yahoo.com> *
+* Vincent Mihalkovic <vmihalko@redhat.com> *
* *
***********************************************************************/
/*
@@ -353,7 +354,8 @@ int sh_histinit(void)
if(fd>=0)
{
fcntl(fd,F_SETFD,FD_CLOEXEC);
- hp->tty = sh_strdup(isatty(2)?ttyname(2):"notty");
+ const char* tty = ttyname(2);
+ hp->tty = sh_strdup(tty?tty:"notty");
hp->auditfp = sfnew(NULL,NULL,-1,fd,SF_WRITE);
}
}

View File

@ -1,23 +1,30 @@
%global verBetaPrefix 1.0.0
%global verBetaSuffix 1
%global verBetaFull %{verBetaPrefix}-beta.%{verBetaSuffix}
Name: ksh
Summary: The Original ATT Korn Shell
URL: http://www.kornshell.com/
License: EPL-1.0
Epoch: 3
Version: %{verBetaPrefix}~beta.%{verBetaSuffix}
Version: 1.0.6
Release: 3%{?dist}
Source0: https://github.com/ksh93/%{name}/archive/v%{verBetaFull}/%{name}-%{verBetaFull}.tar.gz
Source0: https://github.com/ksh93/%{name}/archive/v%{version}/%{name}-%{version}.tar.gz
Source1: kshcomp.conf
Source2: kshrc.rhs
Source3: dotkshrc
# temporary commenting out failing tests
Patch1: %{name}-%{verBetaFull}-regre-tests.patch
# https://github.com/ksh93/ksh/commit/11177d448dadc7f8300e1db60c4ea5bdd61f13e0
Patch2: %{name}-%{verBetaFull}-unset-PWD-segfault.patch
# The alarm builtin hase been temporarily removed from ksh in version 1.0.0.
# To prevent customer regressions we revert following upstream commits:
# https://github.com/ksh93/ksh/commit/4d50b69cbd5fce91d1f3c527dc170e192ceb4760
# https://github.com/ksh93/ksh/commit/b369f40ded0ec7e8dd3d4a0e7226ccf037bb3400
# https://github.com/ksh93/ksh/commit/3688842b7291db6fccdb44ff8e99ab8d4c1b2508
Patch1: %{name}-1.0.6-alarm-1.patch
# alarm builtin was removed as it was unclear if it could ever be fixed
# alarm fixing patch from https://github.com/ksh93/ksh/issues/422#issuecomment-1581168550
Patch2: %{name}-1.0.6-alarm-2.patch
#https://github.com/ksh93/ksh/commit/2075b2b96208ac8b989ca316dcdd674c3f488e2b
Patch3: %{name}-1.0.7-history-trim.patch
#upstream commit: https://github.com/ksh93/ksh/commit/9eb8532ccacf1cfdb7ba18f51eba68776852ef7c.patch
Patch4: ksh-1.0.7-segfault-strdup.patch
Conflicts: pdksh
Requires: coreutils, diffutils
@ -38,23 +45,20 @@ KornShell is a shell programming language, which is upward compatible
with "sh" (the Bourne Shell).
%prep
%autosetup -n %{name}-%{verBetaFull} -p1
%autosetup -p1
#/dev/fd test does not work because of mock
sed -i 's|ls /dev/fd|ls /proc/self/fd|' src/cmd/ksh93/features/options
# disable register for debugging
sed -i 1i"#define register" src/lib/libast/include/ast.h
%build
%set_build_flags
XTRAFLAGS=""
for f in -Wno-unknown-pragmas -Wno-missing-braces -Wno-unused-result -Wno-return-type -Wno-int-to-pointer-cast -Wno-parentheses -Wno-unused -Wno-unused-but-set-variable -Wno-cpp -Wno-maybe-uninitialized -Wno-lto-type-mismatch -P
for f in -Wno-unknown-pragmas -Wno-missing-braces -Wno-unused-result -Wno-return-type -Wno-int-to-pointer-cast -Wno-parentheses -Wno-unused -Wno-unused-but-set-variable -Wno-cpp -Wno-maybe-uninitialized -Wno-lto-type-mismatch
do
$CC $f -E - </dev/null >/dev/null 2>&1 && XTRAFLAGS="$XTRAFLAGS $f"
done
export CCFLAGS="$RPM_OPT_FLAGS $RPM_LD_FLAGS -fno-strict-aliasing $XTRAFLAGS"
./bin/package make -S
export CCFLAGS="$RPM_OPT_FLAGS -fno-strict-aliasing $XTRAFLAGS"
export LDFLAGS="$RPM_LD_FLAGS"
./bin/package make
%install
mkdir -p %{buildroot}{/bin,%{_bindir},%{_mandir}/man1}
@ -143,6 +147,19 @@ fi
%config(noreplace) %{_sysconfdir}/binfmt.d/kshcomp.conf
%changelog
* Sat Feb 10 2024 Vincent Mihalkovic <vmihalko@redhat.com> - 3:1.0.6-3
- Fix segfault in strdup
Resolves: RHEL-25019
* Wed Jan 03 2024 Vincent Mihalkovic <vmihalko@redhat.com> - 3:1.0.6-2
- Fix crash on failure to trim ~/.sh_history (#20345)
* Mon Sep 18 2023 Vincent Mihalkovic <vmihalko@redhat.com> - 3:1.0.6-1
- Rebase to non-beta version, because upstream says it should to be used
https://github.com/ksh93/ksh/issues/667#issuecomment-1653665697
- fix acl test case regression
Resolves: #2034188
* Tue Jun 27 2023 Vincent Mihalkovic <vmihalko@redhat.com> - 3:1.0.0~beta.1-3
- fix segfault when PWD is unset
Resolves: #2123066