This is an automated email from the ASF dual-hosted git repository.

xiaoxiang781216 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 6c1feb78399 sched/addrenv: do not dereference a NULL address 
environment
6c1feb78399 is described below

commit 6c1feb783997f20321f8b23f6a0cdac38a3b9cad
Author: Marco Casaroli <[email protected]>
AuthorDate: Sun Jul 26 11:59:48 2026 +0200

    sched/addrenv: do not dereference a NULL address environment
    
    A task does not necessarily own an address environment.  tcb->addrenv_own is
    set only by addrenv_attach(), which is reached only from addrenv_allocate();
    a kernel thread never allocates one, and in a protected build nothing does 
--
    there is a single address space for the whole system and the architecture's
    up_addrenv_*() are stubs.  addrenv_own is then NULL for every task, always.
    
    That a task may have no address environment is already an expected state.
    addrenv_switch() returns OK when tcb->addrenv_curr is NULL and 
addrenv_drop()
    returns early, and every caller of addrenv_select() checks addrenv_own != 
NULL
    before calling in:  nxsched_get_stateinfo(), nxtask_argvstr(), 
proc_groupenv()
    and the arm, arm64, risc-v and tricore up_check_tcbstack().
    
    addrenv_take() and addrenv_give() are the only two that dereference
    unconditionally.  addrenv_join() calls addrenv_take(ptcb->addrenv_own) 
without
    a check, so pthread_create() faults on &((struct addrenv_s *)NULL)->refs
    whenever the calling task has no address environment.  With
    CONFIG_DEBUG_ASSERTIONS off the same access silently corrupts low memory
    instead.
    
    Handle NULL in both, the way the rest of the file already does.
    addrenv_give() returns a non-zero count for the NULL case so that callers
    never conclude an absent address environment has become unreferenced and
    should be destroyed.
    
    Signed-off-by: Marco Casaroli <[email protected]>
    
    Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
---
 sched/addrenv/addrenv.c | 19 +++++++++++++++++--
 1 file changed, 17 insertions(+), 2 deletions(-)

diff --git a/sched/addrenv/addrenv.c b/sched/addrenv/addrenv.c
index ba0ddb218b8..9936a105c77 100644
--- a/sched/addrenv/addrenv.c
+++ b/sched/addrenv/addrenv.c
@@ -395,7 +395,17 @@ int addrenv_restore(FAR struct addrenv_s *addrenv)
 
 void addrenv_take(FAR struct addrenv_s *addrenv)
 {
-  atomic_fetch_add(&addrenv->refs, 1);
+  /* A task can legitimately have no address environment -- addrenv_switch()
+   * and addrenv_drop() both treat that as "nothing to do".  A kernel thread
+   * never owns one, and in a protected build no task does:  there is a
+   * single address space for the whole system and the architecture's
+   * up_addrenv_*() are stubs.  There is then nothing to reference count.
+   */
+
+  if (addrenv != NULL)
+    {
+      atomic_fetch_add(&addrenv->refs, 1);
+    }
 }
 
 /****************************************************************************
@@ -415,7 +425,12 @@ void addrenv_take(FAR struct addrenv_s *addrenv)
 
 int addrenv_give(FAR struct addrenv_s *addrenv)
 {
-  return atomic_fetch_sub(&addrenv->refs, 1) - 1;
+  /* See addrenv_take():  nothing was counted, so nothing is given back.  A
+   * non-zero count is returned so that callers never conclude the (absent)
+   * address environment has become unreferenced and should be destroyed.
+   */
+
+  return addrenv ? atomic_fetch_sub(&addrenv->refs, 1) - 1 : 1;
 }
 
 /****************************************************************************

Reply via email to