Re-read the refinement call cache set after growing it

rb_vm_insert_cc_refinement() kept a pointer into the embedded data of
vm->cc_refinement_set across the realloc of its entries.  Under
GC.stress, ruby_xrealloc2_sized() runs a GC first, and when that GC
compacts and moves the set, the new buffer and capacity are written to
the abandoned slot while the moved set keeps the freed buffer.  The next
growth then reallocates freed memory, or the weak reference pass of the
next GC walks it.

[Bug #22397]

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Shugo MaedaandClaude Fable 5.1 authored and Shugo Maeda committed 2026-09-30 20:53:44 +09:00
1 parent e131720215
commit dd7be7ce69
1 file changed
+5 -1
Notes: git 2026-09-30 11:54:17 +00:00
+5 -1
View File
@@ -829,7 +829,11 @@ rb_vm_insert_cc_refinement(const struct rb_callcache *cc)
struct cc_refinement_entries *e = RTYPEDDATA_GET_DATA(vm->cc_refinement_set);
if (e->len == e->capa) {
size_t new_capa = e->capa == 0 ? 16 : e->capa * 2;
SIZED_REALLOC_N(e->entries, VALUE, new_capa, e->capa);
VALUE *entries = e->entries;
SIZED_REALLOC_N(entries, VALUE, new_capa, e->capa);
/* The realloc may run a compacting GC, which moves the embedded entries. */
e = RTYPEDDATA_GET_DATA(vm->cc_refinement_set);
e->entries = entries;
e->capa = new_capa;
}
e->entries[e->len++] = (VALUE)cc;