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