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 <noreply@anthropic.com>
This commit is contained in:
Yukihiro "Matz" Matsumoto
2026-05-29 05:59:14 +09:00
parent dad7c0fa36
commit be36b67a12
+10
View File
@@ -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 */