This is an automated email from the ASF dual-hosted git repository.
acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new b6dab5121a3 binfmt: Do not make the exec caller a child of the new
image.
b6dab5121a3 is described below
commit b6dab5121a3f76120a43fe5ef2484e04a4154db8
Author: Marco Casaroli <[email protected]>
AuthorDate: Mon Oct 12 18:06:38 2026 +0200
binfmt: Do not make the exec caller a child of the new image.
exec_swap() gives the new image the pid of the caller and reverses the
parent-child relationship: the caller becomes a child of the new
image, and the caller then exits. The new image got SIGCHLD and a
child status for a process that it did not create. wait() in a
program that a shell started with fork() and exec() returned that pid
instead of failing with ECHILD, and the SIGCHLD interrupted its system
calls.
Give the caller no parent and remove its status from the new image.
Assisted-by: Claude Code:claude-opus-5-5
Signed-off-by: Marco Casaroli <[email protected]>
---
binfmt/binfmt_execmodule.c | 32 ++++++++++++++++++++++++++------
1 file changed, 26 insertions(+), 6 deletions(-)
diff --git a/binfmt/binfmt_execmodule.c b/binfmt/binfmt_execmodule.c
index 5a755711c19..6704572ddd4 100644
--- a/binfmt/binfmt_execmodule.c
+++ b/binfmt/binfmt_execmodule.c
@@ -40,6 +40,7 @@
#include <nuttx/kmalloc.h>
#include <nuttx/sched.h>
#include <nuttx/tls.h>
+#include <group/group.h>
#include <sched/sched.h>
#include <task/spawn.h>
#include <nuttx/spawn.h>
@@ -85,9 +86,9 @@ static void exec_swap(FAR struct tcb_s *ptcb, FAR struct
tcb_s *chtcb)
#endif
#ifdef CONFIG_SCHED_HAVE_PARENT
# ifdef CONFIG_SCHED_CHILD_STATUS
- FAR struct child_status_s *tg_children;
+ FAR struct child_status_s *child;
# else
- uint16_t tg_nchildren;
+ uint16_t nchildren;
# endif
#endif
@@ -125,18 +126,37 @@ static void exec_swap(FAR struct tcb_s *ptcb, FAR struct
tcb_s *chtcb)
#ifdef CONFIG_SCHED_HAVE_PARENT
# ifdef CONFIG_SCHED_CHILD_STATUS
- tg_children = chtcb->group->tg_children;
+ child = chtcb->group->tg_children;
chtcb->group->tg_children = ptcb->group->tg_children;
- ptcb->group->tg_children = tg_children;
+ ptcb->group->tg_children = child;
# else
- tg_nchildren = chtcb->group->tg_nchildren;
+ nchildren = chtcb->group->tg_nchildren;
chtcb->group->tg_nchildren = ptcb->group->tg_nchildren;
- ptcb->group->tg_nchildren = tg_nchildren;
+ ptcb->group->tg_nchildren = nchildren;
# endif
#endif
+ /* The caller exits when the new image starts: it is not a child of the
+ * new image. Without a parent, its exit sends no SIGCHLD to the new
+ * image and leaves no status that wait() in the new image returns.
+ */
+
+ ptcb->group->tg_ppid = INVALID_PROCESS_ID;
+
+#if defined(CONFIG_SCHED_HAVE_PARENT) && !defined(CONFIG_SCHED_CHILD_STATUS)
+ if (chtcb->group->tg_nchildren > 0)
+ {
+ chtcb->group->tg_nchildren--;
+ }
+#endif
+
leave_critical_section(flags);
+#if defined(CONFIG_SCHED_HAVE_PARENT) && defined(CONFIG_SCHED_CHILD_STATUS)
+ child = group_remove_child(chtcb->group, ptcb->pid);
+ group_free_child(child);
+#endif
+
/* getpid() and gettid() read copies of the pids in TLS. The address
* environment of the child is current here, and the TLS of the caller
* is in its own.