git: 5c37f7d22fa7 - stable/14 - wordexp(3): Handle ECHILD from waitpid
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 12 Aug 2025 21:20:04 UTC
The branch stable/14 has been updated by jilles:
URL: https://cgit.FreeBSD.org/src/commit/?id=5c37f7d22fa7edd03b6cd012cb73fa6cac0880ad
commit 5c37f7d22fa7edd03b6cd012cb73fa6cac0880ad
Author: Kenny Levinsen <kl@kl.wtf>
AuthorDate: 2025-04-21 12:13:43 +0000
Commit: Jilles Tjoelker <jilles@FreeBSD.org>
CommitDate: 2025-08-12 21:18:42 +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 <kl@kl.wtf>
Tested by: Jan Beich
Pull Request: https://github.com/freebsd/freebsd-src/pull/1675
(cherry picked from commit da9e73e5d483c47e67b3094356dd4b640749849e)
---
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);