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

commit c2c6ffbd7dff932c6270c01786b3d833be146783
Author: Marco Casaroli <[email protected]>
AuthorDate: Sat Oct 24 11:16:12 2026 +0200

    sched/task: Undo the scheduler setup when nxtask_init() fails.
    
    nxtask_setup_scheduler() gives the TCB a PID and puts it on the inactive
    task list.  When a later step of nxtask_init() failed (tls_init_info()
    or nxtask_setup_stackargs()), the error path left both in place, and the
    caller then freed the TCB with kmm_free().  The PID hash table and the
    inactive task list kept a pointer to freed memory, and the next task
    creation could crash the kernel.  The kernel stack of the new task also
    leaked.
    
    On failure, take the TCB off the inactive task list, release its PID and
    free its kernel stack before the group is released.
    
    Assisted-by: Claude Code:claude-opus-5-5
    Signed-off-by: Marco Casaroli <[email protected]>
---
 sched/sched/sched.h            |  1 +
 sched/sched/sched_releasetcb.c |  8 ++------
 sched/task/task_init.c         | 26 +++++++++++++++++++++++---
 3 files changed, 26 insertions(+), 9 deletions(-)

diff --git a/sched/sched/sched.h b/sched/sched/sched.h
index bd61caf97b3..54bf13d6828 100644
--- a/sched/sched/sched.h
+++ b/sched/sched/sched.h
@@ -321,6 +321,7 @@ void nxsched_remove_self(FAR struct tcb_s *rtrtcb);
 void nxsched_add_blocked(FAR struct tcb_s *btcb, tstate_t task_state);
 void nxsched_remove_blocked(FAR struct tcb_s *btcb);
 int  nxsched_set_priority(FAR struct tcb_s *tcb, int sched_priority);
+void nxsched_releasepid(pid_t pid);
 
 /* Release the vfork() parent suspended on this child, if there is one.
  * Called from nxsched_release_tcb(), the last point in the child's life --
diff --git a/sched/sched/sched_releasetcb.c b/sched/sched/sched_releasetcb.c
index 1f9d8fe1293..a68a14df8ea 100644
--- a/sched/sched/sched_releasetcb.c
+++ b/sched/sched/sched_releasetcb.c
@@ -39,7 +39,7 @@
 #include "timer/timer.h"
 
 /****************************************************************************
- * Private Functions
+ * Public Functions
  ****************************************************************************/
 
 /****************************************************************************
@@ -49,7 +49,7 @@
  * be called to make its process ID available for reuse.
  ****************************************************************************/
 
-static void nxsched_releasepid(pid_t pid)
+void nxsched_releasepid(pid_t pid)
 {
   irqstate_t flags = enter_critical_section();
   int hash_ndx = PIDHASH(pid);
@@ -72,10 +72,6 @@ static void nxsched_releasepid(pid_t pid)
   leave_critical_section(flags);
 }
 
-/****************************************************************************
- * Public Functions
- ****************************************************************************/
-
 /****************************************************************************
  * Name: nxsched_release_tcb
  *
diff --git a/sched/task/task_init.c b/sched/task/task_init.c
index 8af86f498cf..5c24e04aa54 100644
--- a/sched/task/task_init.c
+++ b/sched/task/task_init.c
@@ -79,9 +79,9 @@
  * Returned Value:
  *   OK on success; negative error value on failure appropriately.  (See
  *   nxtask_setup_scheduler() for possible failure conditions).  On failure,
- *   the caller is responsible for freeing the stack memory and for calling
- *   nxsched_release_tcb() to free the TCB (which could be in most any
- *   state).
+ *   nxtask_init() undoes what it did (the PID, the inactive task list,
+ *   the kernel stack, the group) and the caller frees the TCB with
+ *   kmm_free(), and a pre-allocated stack.
  *
  ****************************************************************************/
 
@@ -209,6 +209,26 @@ int nxtask_init(FAR struct tcb_s *tcb, const char *name, 
int priority,
   return ret;
 
 errout_with_group:
+  if (tcb->pid != 0)
+    {
+      irqstate_t flags;
+
+      /* nxtask_setup_scheduler() gave the TCB a PID and put it on the
+       * inactive task list.  The caller frees the TCB: take it off both.
+       */
+
+      flags = enter_critical_section();
+      dq_rem((FAR dq_entry_t *)tcb, list_inactivetasks());
+      leave_critical_section(flags);
+
+      nxsched_releasepid(tcb->pid);
+      tcb->pid = 0;
+    }
+
+#if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_ARCH_KERNEL_STACK)
+  up_addrenv_kstackfree(tcb);
+#endif
+
   if (!stack && tcb->stack_alloc_ptr)
     {
 #ifdef CONFIG_BUILD_KERNEL

Reply via email to