[kernel/mutex] fix: reject deleted mutex waiters - #11730
Conversation
|
👋 感谢您对 RT-Thread 的贡献!Thank you for your contribution to RT-Thread! 为确保代码符合 RT-Thread 的编码规范,请在你的仓库中执行以下步骤运行代码格式化工作流(如果格式化CI运行失败)。 🛠 操作步骤 | Steps
完成后,提交将自动更新至 如有问题欢迎联系我们,再次感谢您的贡献!💐 |
📌 Code Review Assignment🏷️ Tag: kernelReviewers: @GorrayLi @ReviewSun @hamburger-os @lianux-mm @wdfk-prog @xu18838022837 Changed Files (Click to expand)
📊 Current Review Status (Last Updated: 2026-08-23 01:43 CST)
📝 Review Instructions
|
|
|
Move mutex-specific waiter cleanup before a waiter enters the READY state. Whichever path wins wakeup ownership—delete/detach, timeout, or normal mutex release—cleans the mutex wait list and priority-inheritance state, then drops pending_object before the waiter can resume without the mutex lifetime being guaranteed. Return timeout and deletion errors without dereferencing a stale mutex, retry later waiters when a timeout-owned waiter is encountered, and add deterministic regression coverage for both timeout ownership states.
11e636e to
cbde064
Compare
都改了, 也增加了新的 测试, 新版本 可以再review下 |
A mutex waiter could continue accessing a mutex after the object had been
deleted, detached, or otherwise lost its lifetime guarantee. In particular,
the waiter still relied on the mutex after returning from rt_schedule() to
perform priority-inheritance and wait-list cleanup.
This created several lifetime races:
or reuse the mutex before the waiter resumed.
could then be deleted before the waiter resumed from rt_schedule().
that already owned the waiter's timer wakeup.
Move mutex-specific waiter cleanup before the waiter can resume without a
valid mutex lifetime.
Introduce rt_mutex_cleanup_waiter() to remove mutex wait-list state, update
mutex/owner priority inheritance state, and clear pending_object while the
scheduler lock is held.
The timeout path now performs this cleanup before inserting the waiter into
the ready queue. The delete/detach and release paths use
rt_sched_thread_ready() to determine whether they or the timeout path own the
wakeup. If the timeout already owns the wakeup, only the mutex-specific state
is cleaned and the timeout callback remains responsible for making the thread
READY.
After rt_schedule() returns, a waiter whose pending_object has already been
cleared can return its timeout or deletion error without dereferencing the
mutex again.
Reproduction with the original regression test applied to the parent version:
pc=0x6007a7bc and r00/r03=0xa5a5a5a5.
rt_sched_thread_get_curr_prio() [src/scheduler_comm.c:125]
_rt_mutex_take() [src/ipc.c:1489]
rt_mutex_take() [src/ipc.c:1542]
mutex_waiter_entry() [src/utest/mutex_tc.c:919]
Add regression coverage for:
valid waiter.
Validation:
core.mutex/test_mutex_delete_waiter triggered a data abort.
core.mutex passed, including the mutex lifetime regression tests.
为什么提交这份PR (why to submit this PR)
修复 mutex waiter 在 mutex 生命周期结束后仍可能继续访问 mutex 的问题。
原实现中,waiter 从
rt_schedule()恢复后,错误路径仍需要访问 mutex,用于更新等待队列、mutex priority 以及 owner 的优先级继承状态。因此存在以下
生命周期竞态:
rt_mutex_delete()/rt_mutex_detach()唤醒 waiter 后,在 waiter真正恢复执行之前释放或复用 mutex,waiter 随后继续访问失效对象。
waiter timeout 后已经离开 mutex suspend list 并进入 READY,但尚未得到
CPU。此时其他线程删除 mutex,waiter 随后恢复时仍可能访问已经释放的
mutex。
delete/detach 或
rt_mutex_release()与 timeout callback 同时竞争同一个waiter 的 wakeup ownership 时,如果 mutex cleanup 与 READY 状态转换没有
正确协调,仍可能留下 stale
pending_object或错误的 PI 状态。这些情况都可能导致 use-after-free、data abort,或者 mutex priority
inheritance 状态不一致。
你的解决方案是什么 (what is your solution)
新增
rt_mutex_cleanup_waiter(),在持有 scheduler lock 的情况下统一完成mutex waiter 的清理:
thread->pending_object。将 timeout 的 mutex-specific cleanup 前移到 waiter 进入 READY 之前。
_thread_timeout()在将线程插入 ready queue 前调用rt_mutex_cleanup_waiter()。因此 timeout waiter 一旦进入 READY,就已经不再需要访问原 mutex。
在 delete/detach 路径使用
rt_sched_thread_ready()判断 wakeup ownership。rt_sched_thread_ready()成功,说明 delete/detach 赢得 wakeup race,在同一个 scheduler-lock 状态转换中完成 mutex cleanup,并设置
RT_ERROR。delete/detach 只清理 mutex-specific 状态和
pending_object,仍由 timeoutcallback 负责最终将线程变为 READY。
调整
rt_mutex_release()的 waiter 选择逻辑。当队首 waiter 的 timeout 已经取得 wakeup ownership 时,不再错误地把它当作
正常 mutex recipient,而是先清理该 waiter 的 mutex 状态,再继续选择下一个
有效 waiter。
_rt_mutex_take()从rt_schedule()返回后,如果发现pending_object == RT_NULL且错误为删除或 timeout 错误,则直接返回对应error,不再重新解引用 mutex。
补充回归测试,覆盖:
请提供验证的bsp和config (provide the config and bsp)
BSP:
bsp/qemu-vexpress-a9.config:
RT_USING_HEAP以运行动态 mutex 相关测试Validation:
core.mutex/test_mutex_delete_waiter可触发 data abort,PC 位于
rt_sched_thread_get_curr_prio(),复用后的 mutex 内容为0xa5a5a5a5。core.mutex通过,包括 delete/detach、timeout READY lifetime race 和timeout/release ownership 相关回归测试。
scons -j$(nproc) --strict -C bsp/qemu-vexpress-a9通过。action:
当前拉取/合并请求的状态 Intent for your PR
必须选择一项 Choose one (Mandatory):
代码质量 Code Quality:
我在这个拉取/合并请求中已经考虑了 As part of this pull request, I've considered the following:
#if 0代码,不包含已经被注释了的代码 All redundant code is removed and cleaned up