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; }
