mirror of
https://github.com/apache/nuttx.git
synced 2026-08-02 12:49:00 +00:00
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 <marco.casaroli@gmail.com> Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
7fd17c9d7c
commit
6c1feb7839
1 changed files with 17 additions and 2 deletions
|
|
@ -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;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue