diff --git a/string.c b/string.c index 13ca9b33d5e12e..662987431eb9e4 100644 --- a/string.c +++ b/string.c @@ -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; @@ -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); @@ -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); diff --git a/test/ruby/test_string.rb b/test/ruby/test_string.rb index fdf23ad90b4d98..2ccabcbe80ab6d 100644 --- a/test/ruby/test_string.rb +++ b/test/ruby/test_string.rb @@ -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("hll"), S("hello").gsub(/([aeiou])/, S('<\1>'))) } + end + def test_gsub_encoding a = S("hello world") a.force_encoding Encoding::UTF_8 @@ -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("hll"), a) + end + end + def test_sub_hash assert_equal('azc', S('abc').sub(/b/, "b" => "z")) assert_equal('ac', S('abc').sub(/b/, {}))