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 1b812de553f47f4388ddf14d3c3c7246f1d983a2
Author: Marco Casaroli <[email protected]>
AuthorDate: Thu Oct 29 12:27:06 2026 +0100

    libs/libc/unistd: Hold the task information lock during fork().
    
    The child of fork() uses its copy of the task information of the
    parent: the environment, the exit functions, the fork handlers and the
    keys.  If another thread of the parent changed one of these during the
    copy, the copy was not consistent.  Also, the lock of the copy could be
    held by a thread that is not in the child, and the next lock of it in
    the child did not return.
    
    fork() now holds the lock from the end of the prepare handlers to the
    end of the copy.  The child initializes its copy of the lock again,
    because the holder of the copy is a thread of the parent.  The parent
    releases the lock before the parent handlers.  fork() takes the lock
    after the prepare handlers and releases it before the parent handlers,
    so this adds no new lock order between the lock and the mutexes that
    the handlers lock.
    
    Assisted-by: Claude Code:claude-opus-5-5
    Signed-off-by: Marco Casaroli <[email protected]>
---
 libs/libc/unistd/lib_fork.c | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/libs/libc/unistd/lib_fork.c b/libs/libc/unistd/lib_fork.c
index 29cd14a123f..ac72025ea7f 100644
--- a/libs/libc/unistd/lib_fork.c
+++ b/libs/libc/unistd/lib_fork.c
@@ -207,23 +207,37 @@ pid_t vfork(void)
 #ifdef CONFIG_ARCH_HAVE_FORK
 pid_t fork(void)
 {
+  FAR struct task_info_s *info = task_get_info();
   pid_t pid;
 
 #ifdef CONFIG_PTHREAD_ATFORK
   atfork_prepare();
 #endif
+
+  /* Hold the lock of the task information during the copy.  Then no other
+   * thread changes the environment, the exit functions or the fork
+   * handlers while the child gets its copy of them.
+   */
+
+  nxrmutex_lock(&info->ta_lock);
   pid = up_fork(false);
 
-#ifdef CONFIG_PTHREAD_ATFORK
   if (pid == 0)
     {
+      /* The copy of the lock has a holder that is not in the child */
+
+      nxrmutex_init(&info->ta_lock);
+#ifdef CONFIG_PTHREAD_ATFORK
       atfork_child();
+#endif
     }
   else
     {
+      nxrmutex_unlock(&info->ta_lock);
+#ifdef CONFIG_PTHREAD_ATFORK
       atfork_parent();
-    }
 #endif
+    }
 
   return pid;
 }

Reply via email to