From be36b67a128e2fb498588f12c42e13869d38abb6 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 29 May 2026 05:59:14 +0900 Subject: [PATCH] mruby-task: clear dead stack slots when marking preempted tasks mrb_task_mark_all marked a task's live registers but, unlike mark_context_stack in gc.c, never cleared the slots above the live range. When a preempted task's live range later shrank (a frame had returned), the stale object pointers left in those slots were neither marked nor cleared: the objects were swept while the pointers survived. Re-entering the same frame reused those slots, and the next mark of the resumed task hit a freed object, tripping the MRB_TT_FREE assertion in mrb_gc_mark. Clear the dead slots after marking, exactly as mark_context_stack does for the running context. Fixes #6870. Co-authored-by: Claude --- mrbgems/mruby-task/src/task.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/mrbgems/mruby-task/src/task.c b/mrbgems/mruby-task/src/task.c index 5aa47c1ef..28a89ee37 100644 --- a/mrbgems/mruby-task/src/task.c +++ b/mrbgems/mruby-task/src/task.c @@ -94,6 +94,16 @@ mrb_task_mark_all(mrb_state *mrb) for (i = 0; i < e; i++) { mrb_gc_mark_value(mrb, c->stbase[i]); } + /* Clear the dead slots above the live range, matching + mark_context_stack() in gc.c. A preempted task whose live range + later shrinks (a frame returned) would otherwise leave stale + object pointers in those slots; the objects get swept while the + pointers survive, and a subsequent mark of the resumed task trips + the MRB_TT_FREE assertion in mrb_gc_mark (issue #6870). */ + size_t stend = c->stend - c->stbase; + for (; i < stend; i++) { + SET_NIL_VALUE(c->stbase[i]); + } } /* Mark call stack */