mruby-regexp: keep MatchData source/regexp GC-reachable

The mrb_match_data struct stores `source` and `regexp` as plain
mrb_value members of a C-allocated struct, which the GC does not
scan.  Under MRB_GC_STRESS the source string could be collected
while the MatchData was still alive, causing md[0] to read freed
memory (observed as "\xff\xff\xff").

Also stash source and regexp as instance variables on the MatchData
object so they remain reachable via the object's iv_tbl during GC.
The C struct members continue to provide fast direct access, and
no other call sites need to change.

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Yukihiro "Matz" Matsumoto
2026-04-15 08:15:42 +09:00
parent eb5480a6b3
commit 449040400a
+5
View File
@@ -172,6 +172,11 @@ create_matchdata(mrb_state *mrb, mrb_value regexp, mrb_value str, int *captures,
memcpy(md->captures, captures, sizeof(int) * ncap);
mrb_value obj = mrb_obj_value(mrb_data_object_alloc(mrb, md_class, md, &matchdata_type));
/* Keep `source` and `regexp` GC-reachable via instance variables.
* The mrb_values are also held in mrb_match_data, but C-allocated
* structs are not scanned by the GC. */
mrb_iv_set(mrb, obj, mrb_intern_lit(mrb, "source"), str);
mrb_iv_set(mrb, obj, mrb_intern_lit(mrb, "regexp"), regexp);
mrb_gv_set(mrb, mrb_intern_lit(mrb, "$~"), obj);
/* set $1-$9 from captures */