ksh/ksh-1.0.10-issue-951-comsub-nested-func.patch
2026-03-25 12:09:20 +01:00

148 lines
4.5 KiB
Diff
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

From 99028e9f709ee44f7c730d2883e31e37adab4d57 Mon Sep 17 00:00:00 2001
From: Martijn Dekker <martijn@inlv.org>
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 calls 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