Fishwaldo opened a new pull request, #19733:
URL: https://github.com/apache/nuttx/pull/19733

   ## Summary
   
     * In a kernel build with assertions enabled, every exit of a process that
       frees memory panics in `sem_post`. No program can be run twice, and
       running one at all takes the shell down with it.
     * A mutex records its holder as a task id in the low 31 bits of a word
       whose top bit means "someone is blocked on this". The id was stored
       without masking, so an id with its top bit set became a holder with the
       blocking bit raised.
     * Task ids are normally small and positive, but not always.
       `nxsched_gettid()` reports `-ESRCH` for a context that no longer maps to
       a running task, and there is a window where that is exactly what the
       running context is: `nxtask_exit()` marks the next task ready to run
       while the dying task is still executing on its own stack, and only then
       releases the TCB. Freeing the group inside that release takes and drops
       the group's mutexes, so the lock stores `0xfffffffd` and the unlock
       compares `0x7ffffffd`, which are not equal.
     * This is not specific to a build mode. `nxsched_gettid()` returns `-ESRCH`
       whenever the task at the head of the ready-to-run list is not
       `TSTATE_TASK_RUNNING`, which is generic scheduler behaviour. Kernel 
builds
       merely hit the window on essentially every process exit, since tearing
       down a process frees memory inside it, and that is where it was found.
     * With assertions off it is quieter and worse: the accidental blocking bit
       sends the unlock looking for a waiter that never existed.
     * The fix encodes the id the same way everywhere it is stored or compared,
       so a lock and an unlock from one context agree whatever the id's sign.
     * `mm_lock()` already sidesteps this window with a note that `gettid()` may
       return `-ESRCH` during a context switch. This gives the generic mutex the
       same footing rather than leaving a second special case.
     * The masked forms of -1 and -2 would alias the `NXSEM_MRESET` and
       `NXSEM_NO_MHOLDER` sentinels, but `nxsched_gettid()` yields only valid
       ids and `-ESRCH`, which is -3.
     * No related issue filed.
   
   ## Impact
   
     * Is new feature added? Is existing feature changed? **NO.** Bug fix.
     * Impact on user? **YES, positive.** Kernel builds with assertions become
       usable: before this, a process that frees memory panics on exit, which in
       a kernel build is every process. No API change.
     * Impact on build? **NO.**
     * Impact on hardware? **NO.** Generic scheduler code.
     * Impact on documentation? **NO.**
     * Impact on security? **Marginally, yes.** With assertions disabled the
       stray blocking bit makes an unlock search for a waiter that does not
       exist, so this removes a source of undefined behaviour on every process
       exit rather than only a noisy assertion.
     * Impact on compatibility? **NO.** Positive task ids encode exactly as
       before; only the sign-extended case changes.
     * Build-mode dependence? **NO.** The wrong encoding is present in flat,
       protected and kernel builds alike. Flat builds reach the teardown window
       less predictably, so the assertion fires less often, but nothing about
       the defect or the fix is conditional on `CONFIG_BUILD_KERNEL`.
   
   ## Testing
   
     I confirm that changes are verified on local setup and works as intended:
   
     * Build Host: macOS 26.5.1, arm64 (Apple Silicon), xPack riscv-none-elf-gcc
       15.2.0
     * Target: RISC-V, ESWIN EIC7700X EVB (downstream board port, not yet
       upstream), kernel build, assertions enabled
   
     Any process exit that frees memory triggers it. The command in hand at the
     time was `i2c bus`.
   
     Testing logs before change:
   
     ```
     nsh> i2c bus
     BUS   EXISTS?
     [CPU1] dump_assert_info: Current Version: NuttX  13.0.0 beecb96e98 Aug  4 
2026 17:58:09 risc-v
     [CPU1] dump_assert_info: Assertion failed mholder == 
(((uint32_t)0x80000000) | ((uint32_t)0x7fffffff)) || (mholder & 
(~((uint32_t)0x80000000))) == nxsched_gettid(): at file: 
semaphore/sem_post.c:105 task(CPU1): /system/bin/init process: /system/bin/init 
0xc000001a
     [CPU1] up_dump_register: EPC: 0000000080204fa2
     ```
   
     The shell does not survive it.
   
     Testing logs after change:
   
     ```
     exit: 0
     asserts: 0
     ##### CMD 1: hello
     Hello, World!!
     ##### END 1 (ok, 1.98s)
     ##### CMD 2: hello
     Hello, World!!
     ##### END 2 (ok, 1.63s)
     ##### CMD 3: hello
     Hello, World!!
     ##### END 3 (ok, 1.52s)
     ##### CMD 4: hello
     Hello, World!!
     ##### END 4 (ok, 1.55s)
     ##### CMD 5: hello
     Hello, World!!
     ##### END 5 (ok, 1.64s)
     ##### CMD 6: i2c bus
     ##### END 6 (ok, 1.64s)
     ##### CMD 7: i2c dev 0x08 0x77 0
     ##### END 7 (ok, 1.54s)
     ```
   
     Five process exits in a row, the shell surviving all of them, and the
     command that previously panicked now completing.
   
   ## PR verification Self-Check
   
     * [x] This PR introduces only one functional change.
     * [x] I have updated all required description fields above.
     * [x] My PR adheres to Contributing Guidelines and Documentation.
     * [ ] My PR is still work in progress (not ready for review).
     * [x] My PR is ready for review and can be safely merged into a codebase.
   
   ---
   
   *Claude (claude-opus-5) assisted with diagnosing this bug and with authoring 
the
   code comments and this PR description. The commit carries an `Assisted-by:` 
tag
   per 
[CONTRIBUTING.md](https://github.com/apache/nuttx/blob/master/CONTRIBUTING.md) 
ยง1.5.*
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to