The branch main has been updated by jilles:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=da9e73e5d483c47e67b3094356dd4b640749849e

commit da9e73e5d483c47e67b3094356dd4b640749849e
Author:     Kenny Levinsen <k...@kl.wtf>
AuthorDate: 2025-04-21 12:13:43 +0000
Commit:     Jilles Tjoelker <jil...@freebsd.org>
CommitDate: 2025-07-08 21:27:33 +0000

    wordexp(3): Handle ECHILD from waitpid
    
    If the calling process has used SIG_IGN as handler or set the
    SA_NOCLDWAIT flag for SIGCHLD, processes will be automatically reaped on
    exit and calls to waitpid(3) will therefore fail with ECHILD.
    
    We waitpid primarily to reap our child so that the caller does not have
    to worry about it. ECHILD indicates that there is no child to reap, so
    we can just treat that as a success and move on.
    
    Signed-off-by: Kenny Levinsen <k...@kl.wtf>
    Tested by: Jan Beich
    Pull Request: https://github.com/freebsd/freebsd-src/pull/1675
---
 lib/libc/gen/wordexp.c            | 10 +++++++++-
 lib/libc/tests/gen/wordexp_test.c | 26 ++++++++++++++++++++++++++
 2 files changed, 35 insertions(+), 1 deletion(-)

diff --git a/lib/libc/gen/wordexp.c b/lib/libc/gen/wordexp.c
index f1437e30bbe2..f8080c20d121 100644
--- a/lib/libc/gen/wordexp.c
+++ b/lib/libc/gen/wordexp.c
@@ -265,7 +265,15 @@ cleanup:
                errno = serrno;
                return (error);
        }
-       if (wpid < 0 || !WIFEXITED(status) || WEXITSTATUS(status) != 0)
+       /*
+        * Check process exit status, but ignore ECHILD as the child may have
+        * been automatically reaped if the process had set SIG_IGN or
+        * SA_NOCLDWAIT for SIGCHLD, and our reason for waitpid was just to
+        * reap our own child on behalf of the calling process.
+        */
+       if (wpid < 0 && errno != ECHILD)
+               return (WRDE_NOSPACE); /* abort for unknown reason */
+       if (wpid >= 0 && (!WIFEXITED(status) || WEXITSTATUS(status) != 0))
                return (WRDE_NOSPACE); /* abort for unknown reason */
 
        /*
diff --git a/lib/libc/tests/gen/wordexp_test.c 
b/lib/libc/tests/gen/wordexp_test.c
index 909097fbf51e..a8b9d5509633 100644
--- a/lib/libc/tests/gen/wordexp_test.c
+++ b/lib/libc/tests/gen/wordexp_test.c
@@ -292,6 +292,31 @@ ATF_TC_BODY(with_SIGCHILD_handler_test, tc)
        ATF_REQUIRE(r == 0);
 }
 
+ATF_TC_WITHOUT_HEAD(with_SIGCHILD_ignore_test);
+ATF_TC_BODY(with_SIGCHILD_ignore_test, tc)
+{
+       struct sigaction sa;
+       wordexp_t we;
+       int r;
+
+       /* With SIGCHLD set to ignore so that the kernel auto-reaps zombies. */
+       sa.sa_flags = 0;
+       sigemptyset(&sa.sa_mask);
+       sa.sa_handler = SIG_IGN;
+       r = sigaction(SIGCHLD, &sa, NULL);
+       ATF_REQUIRE(r == 0);
+       r = wordexp("hello world", &we, 0);
+       ATF_REQUIRE(r == 0);
+       ATF_REQUIRE(we.we_wordc == 2);
+       ATF_REQUIRE(strcmp(we.we_wordv[0], "hello") == 0);
+       ATF_REQUIRE(strcmp(we.we_wordv[1], "world") == 0);
+       ATF_REQUIRE(we.we_wordv[2] == NULL);
+       wordfree(&we);
+       sa.sa_handler = SIG_DFL;
+       r = sigaction(SIGCHLD, &sa, NULL);
+       ATF_REQUIRE(r == 0);
+}
+
 ATF_TC_WITHOUT_HEAD(with_unused_non_default_IFS_test);
 ATF_TC_BODY(with_unused_non_default_IFS_test, tc)
 {
@@ -350,6 +375,7 @@ ATF_TP_ADD_TCS(tp)
        ATF_TP_ADD_TC(tp, WRDE_BADCHAR_test);
        ATF_TP_ADD_TC(tp, WRDE_SYNTAX_test);
        ATF_TP_ADD_TC(tp, with_SIGCHILD_handler_test);
+       ATF_TP_ADD_TC(tp, with_SIGCHILD_ignore_test);
        ATF_TP_ADD_TC(tp, with_unused_non_default_IFS_test);
        ATF_TP_ADD_TC(tp, with_used_non_default_IFS_test);
 

Reply via email to