aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Zhu <peter@peterzhu.ca>2023-11-28 13:50:05 -0500
committerPeter Zhu <peter@peterzhu.ca>2023-11-29 19:21:40 -0500
commit3d908a41ab67e2aeced7dc6b9773a017bb859253 (patch)
tree3c898e637943bb17495bb347baae07e8789d1dab
parent8d1138c1cf087f28510f4532c746e70c54d0f81e (diff)
downloadruby-3d908a41ab67e2aeced7dc6b9773a017bb859253.tar.gz
Guard match from GC in String#gsub
We need to guard match from GC because otherwise it could end up being reclaimed or moved in compaction.
-rw-r--r--string.c9
-rw-r--r--test/ruby/test_string.rb12
2 files changed, 17 insertions, 4 deletions
diff --git a/string.c b/string.c
index 13ca9b33d5..662987431e 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 fdf23ad90b..2ccabcbe80 100644
--- a/test/ruby/test_string.rb
+++ b/test/ruby/test_string.rb
@@ -1249,6 +1249,10 @@ CODE
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
@@ -1292,6 +1296,14 @@ CODE
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/, {}))