diff --git a/ksh-1.0.10-issue-951-comsub-nested-func.patch b/ksh-1.0.10-issue-951-comsub-nested-func.patch new file mode 100644 index 0000000..a86f22c --- /dev/null +++ b/ksh-1.0.10-issue-951-comsub-nested-func.patch @@ -0,0 +1,147 @@ +From 99028e9f709ee44f7c730d2883e31e37adab4d57 Mon Sep 17 00:00:00 2001 +From: Martijn Dekker +Date: Mon, 23 Mar 2026 22:45:04 +0000 +Subject: [PATCH] Fix bug in comsubs involving nested functions with redirects + (re: e373e8c1, 274def65, 0ceb4864, 5def4398) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Vincent Mihalkovič (@vmihalko) from Red Hat reports: +> When executing a function in a subshell: the output is lost when +> a previous line in the function redirects to stderr while not +> having any output. +> +> ### Minimal reproducer +> +> #!/usr/bin/ksh +> function echo_devnull { +> echo "DEVNULL" >/dev/null +> } +> function func { +> echo_devnull >&2 +> echo "FUNC" +> } +> OUT=$(func) +> echo "OUT: ${OUT}" +> +> Expected: 'OUT: FUNC' Actual: 'OUT:' (empty) +> +> In 'OUT=$(func)', output from 'func' is lost when a prior line in +> 'func' runs the customer pattern 'echo_devnull >&2' (redirect +> that call’s stdout to stderr) and 'echo_devnull' itself sends +> stdout to '/dev/null'. The following 'echo "FUNC"' should appear +> in 'OUT' but 'OUT' is empty. bash is OK. + +src/cmd/ksh93/sh/io.c: sh_redirect(): +- Amend the forking workaround yet again. Return to something + closer to the original 93u+ workaround: fork if redirections + persist past the command (flag==1 || flag==2) or standard output + is on an Sfio string buffer. All regression tests pass, so this + should not introduce the 93u+ bugs fixed in the meantime. + +Resolves: https://github.com/ksh93/ksh/issues/951 + +Upstream-commit: 99028e9f709ee44f7c730d2883e31e37adab4d57 +Resolves: RHEL-155803 +--- + src/cmd/ksh93/sh/io.c | 4 +- + src/cmd/ksh93/tests/subshell.sh | 67 +++++++++++++++++++++++++++++++++ + 2 files changed, 68 insertions(+), 3 deletions(-) + +diff --git a/src/cmd/ksh93/sh/io.c b/src/cmd/ksh93/sh/io.c +index ea83132..d54c649 100644 +--- a/src/cmd/ksh93/sh/io.c ++++ b/src/cmd/ksh93/sh/io.c +@@ -1143,10 +1143,8 @@ int sh_redirect(struct ionod *iop, int flag) + * 'redirect'. This forking workaround is necessary to avoid that bug. + * For shared-state comsubs, forking is incorrect, so error out then. + * TODO: actually fix the bug and remove this workaround. +- * (Note that sh.redir0 is set to 1 in xec.c immediately before processing +- * redirections for any built-in command, including 'exec' and 'redirect'.) + */ +- if(sh.subshell && sh.comsub && sh.redir0==1) ++ if(sh.subshell && sh.comsub && (flag==1 || flag==2 || (sfset(sfstdout,0,0) & SFIO_STRING))) + { + struct ionod *i; + for(i = iop; i; i = i->ionxt) +diff --git a/src/cmd/ksh93/tests/subshell.sh b/src/cmd/ksh93/tests/subshell.sh +index 7a91abf..1f896f1 100755 +--- a/src/cmd/ksh93/tests/subshell.sh ++++ b/src/cmd/ksh93/tests/subshell.sh +@@ -1219,5 +1219,72 @@ got=$("$SHELL" -c 'x=$(fn(){ return 265; };echo ok|fn); echo exited $?' 2>&1) + [[ e=$? -eq 0 && $got == "$exp" ]] || err_exit "regression involving SIGPIPE in subshell" \ + "(expected status 0 and $(printf %q "$exp"), got status $e and $(printf %q "$got"))" + ++# ====== ++# Command substitution loses stdout after nested function redirects stdout to /dev/null ++# https://github.com/ksh93/ksh/issues/951 ++ ++got=$( ++ function echo_devnull { ++ echo "DEVNULL" >/dev/null ++ } ++ function func { ++ echo_devnull >&2 ++ echo "FUNC" ++ } ++ OUT=$(func) ++ echo "OUT: ${OUT}" ++) ++exp='OUT: FUNC' ++[[ $got == "$exp" ]] || err_exit "bug 951 test 1a (expected $(printf %q "$exp"), got $(printf %q "$got"))" ++ ++got=$( ++ function echo_devnull { ++ echo "DEVNULL" >/dev/null ++ } ++ function func { ++ echo_devnull >&2 ++ echo "FUNC" ++ } ++ OUT=${ func; } ++ echo "OUT: ${OUT}" ++) ++exp='OUT: FUNC' ++[[ $got == "$exp" ]] || err_exit "bug 951 test 1b (expected $(printf %q "$exp"), got $(printf %q "$got"))" ++ ++got=$( ++ function echo_devnull { ++ ulimit -c 0 ++ } ++ function func { ++ echo_devnull >&2 ++ echo "FUNC" ++ } ++ OUT=$(func) ++ echo "OUT: ${OUT}" ++) ++exp='OUT: FUNC' ++[[ $got == "$exp" ]] || err_exit "bug 951 test 2a (expected $(printf %q "$exp"), got $(printf %q "$got"))" ++ ++got=$( ++ function echo_devnull { ++ ulimit -c 0 ++ } ++ function func { ++ echo_devnull >&2 ++ echo "FUNC" ++ } ++ OUT=${ func; } ++ echo "OUT: ${OUT}" ++) ++exp='OUT: FUNC' ++[[ $got == "$exp" ]] || err_exit "bug 951 test 2b (expected $(printf %q "$exp"), got $(printf %q "$got"))" ++ ++got=$( ++ OUT=$(ulimit -c 0 >&2; echo OK) ++ echo "OUT: ${OUT}" ++) ++exp='OUT: OK' ++[[ $got == "$exp" ]] || err_exit "bug 951 test 3 (expected $(printf %q "$exp"), got $(printf %q "$got"))" ++ + # ====== + exit $((Errors<125?Errors:125)) +-- +2.53.0 + diff --git a/ksh.spec b/ksh.spec index f63691e..16945dd 100644 --- a/ksh.spec +++ b/ksh.spec @@ -4,7 +4,7 @@ URL: http://www.kornshell.com/ License: EPL-2.0 Epoch: 3 Version: 1.0.10 -Release: 9%{?dist} +Release: 10%{?dist} Source0: https://github.com/ksh93/%{name}/archive/v%{version}/%{name}-%{version}.tar.gz Source1: kshcomp.conf Source2: kshrc.rhs @@ -31,6 +31,9 @@ Patch6: ksh-1.0.12-security.patch # upstream commit: https://github.com/ksh93/ksh/commit/c2cfcfc6f4b2d63472b2290debb9d0bb84c932df Patch7: ksh-1.0.11-devfd-memory-fault.patch +# upstream commit: https://github.com/ksh93/ksh/commit/99028e9f709ee44f7c730d2883e31e37adab4d57 +Patch8: ksh-1.0.10-issue-951-comsub-nested-func.patch + Conflicts: pdksh Requires: coreutils, diffutils BuildRequires: gcc @@ -159,6 +162,10 @@ fi %config(noreplace) %{_sysconfdir}/binfmt.d/kshcomp.conf %changelog +* Wed Mar 25 2026 Vincent Mihalkovic - 3:1.0.10-10 +- Fix command substitution with nested functions and redirects + Resolves: RHEL-155803 + * Wed Feb 04 2026 Vincent Mihalkovic - 3:1.0.10-9 - Fix /dev/fd/1 memory fault and $0 for /dev/fd scripts Resolves: RHEL-146565