Skip to content

Commit

Permalink
Guard match from GC in String#gsub
Browse files Browse the repository at this point in the history
We need to guard match from GC because otherwise it could end up being
reclaimed or moved in compaction.
  • Loading branch information
peterzhu2118 committed Nov 30, 2023
1 parent 8d1138c commit 3d908a4
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 4 deletions.
9 changes: 5 additions & 4 deletions string.c
Expand Up @@ -5866,8 +5866,7 @@ rb_str_sub(int argc, VALUE *argv, VALUE str)
static VALUE
str_gsub(int argc, VALUE *argv, VALUE str, int bang)
{
VALUE pat, val = Qnil, repl, match, match0 = Qnil, dest, hash = Qnil;
struct re_registers *regs;
VALUE pat, val = Qnil, repl, match0 = Qnil, dest, hash = Qnil;
long beg, beg0, end0;
long offset, blen, slen, len, last;
enum {STR, ITER, MAP} mode = STR;
Expand Down Expand Up @@ -5912,8 +5911,8 @@ str_gsub(int argc, VALUE *argv, VALUE str, int bang)
ENC_CODERANGE_SET(dest, rb_enc_asciicompat(str_enc) ? ENC_CODERANGE_7BIT : ENC_CODERANGE_VALID);

do {
match = rb_backref_get();
regs = RMATCH_REGS(match);
VALUE match = rb_backref_get();
struct re_registers *regs = RMATCH_REGS(match);
if (RB_TYPE_P(pat, T_STRING)) {
beg0 = beg;
end0 = beg0 + RSTRING_LEN(pat);
Expand Down Expand Up @@ -5970,6 +5969,8 @@ str_gsub(int argc, VALUE *argv, VALUE str, int bang)
cp = RSTRING_PTR(str) + offset;
if (offset > RSTRING_LEN(str)) break;
beg = rb_pat_search(pat, str, offset, need_backref);

RB_GC_GUARD(match);
} while (beg >= 0);
if (RSTRING_LEN(str) > offset) {
rb_enc_str_buf_cat(dest, cp, RSTRING_LEN(str) - offset, str_enc);
Expand Down
12 changes: 12 additions & 0 deletions test/ruby/test_string.rb
Expand Up @@ -1249,6 +1249,10 @@ def test_gsub
assert_raise(ArgumentError) { S("foo").gsub }
end

def test_gsub_gc_compact_stress
EnvUtil.under_gc_compact_stress { assert_equal(S("h<e>ll<o>"), S("hello").gsub(/([aeiou])/, S('<\1>'))) }
end

def test_gsub_encoding
a = S("hello world")
a.force_encoding Encoding::UTF_8
Expand Down Expand Up @@ -1292,6 +1296,14 @@ def test_gsub!
assert_nil(a.sub!(S('X'), S('Y')))
end

def test_gsub_bang_gc_compact_stress
EnvUtil.under_gc_compact_stress do
a = S("hello")
a.gsub!(/([aeiou])/, S('<\1>'))
assert_equal(S("h<e>ll<o>"), a)
end
end

def test_sub_hash
assert_equal('azc', S('abc').sub(/b/, "b" => "z"))
assert_equal('ac', S('abc').sub(/b/, {}))
Expand Down

0 comments on commit 3d908a4

Please sign in to comment.