Guard match from GC when scanning string

We need to guard match from GC because otherwise it could end up being
reclaimed or moved in compaction.
This commit is contained in:
Peter Zhu 2023-11-27 14:45:47 -05:00
parent 1acea50100
commit 94015e0dce
2 changed files with 21 additions and 11 deletions

View File

@ -9973,11 +9973,11 @@ rb_str_strip(VALUE str)
static VALUE
scan_once(VALUE str, VALUE pat, long *start, int set_backref_str)
{
VALUE result, match;
struct re_registers *regs;
int i;
VALUE result = Qnil;
long end, pos = rb_pat_search(pat, str, *start, set_backref_str);
if (pos >= 0) {
VALUE match;
struct re_registers *regs;
if (BUILTIN_TYPE(pat) == T_STRING) {
regs = NULL;
end = pos + RSTRING_LEN(pat);
@ -9988,6 +9988,7 @@ scan_once(VALUE str, VALUE pat, long *start, int set_backref_str)
pos = BEG(0);
end = END(0);
}
if (pos == end) {
rb_encoding *enc = STR_ENC_GET(str);
/*
@ -10002,22 +10003,27 @@ scan_once(VALUE str, VALUE pat, long *start, int set_backref_str)
else {
*start = end;
}
if (!regs || regs->num_regs == 1) {
result = rb_str_subseq(str, pos, end - pos);
return result;
}
result = rb_ary_new2(regs->num_regs);
for (i=1; i < regs->num_regs; i++) {
VALUE s = Qnil;
if (BEG(i) >= 0) {
s = rb_str_subseq(str, BEG(i), END(i)-BEG(i));
else {
result = rb_ary_new2(regs->num_regs);
for (int i = 1; i < regs->num_regs; i++) {
VALUE s = Qnil;
if (BEG(i) >= 0) {
s = rb_str_subseq(str, BEG(i), END(i)-BEG(i));
}
rb_ary_push(result, s);
}
rb_ary_push(result, s);
}
return result;
RB_GC_GUARD(match);
}
return Qnil;
return result;
}

View File

@ -1622,6 +1622,10 @@ CODE
assert_equal(%w[1 2 3], S("a1 a2 a3").scan(/a\K./))
end
def test_scan_gc_compact_stress
EnvUtil.under_gc_compact_stress { assert_equal([["1a"], ["2b"], ["3c"]], S("1a2b3c").scan(/(\d.)/)) }
end
def test_scan_segv
bug19159 = '[Bug #19159]'
assert_nothing_raised(Exception, bug19159) do