From fadda88903d9fe764ae53eca07aaf85f08e162a7 Mon Sep 17 00:00:00 2001 From: Peter Zhu Date: Sat, 23 Dec 2023 14:51:43 -0500 Subject: [PATCH] Fix Regexp#to_s for GC compaction The test fails when RGENGC_CHECK_MODE is turned on: TestRegexp#test_to_s_under_gc_compact_stress = 13.46 s 1) Failure: TestRegexp#test_to_s_under_gc_compact_stress [test/ruby/test_regexp.rb:81]: <"(?-mix:abcd\u3042)"> expected but was <"(?-mix:\u5C78\u3030\u5C78\u3030\u5C78\u3030\u5C78\u3030\u5C78\u3030)">. --- re.c | 9 +++++---- test/ruby/test_regexp.rb | 12 ++++++++++++ 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/re.c b/re.c index f3be9a1fce..e51b782cf6 100644 --- a/re.c +++ b/re.c @@ -565,8 +565,6 @@ rb_reg_str_with_term(VALUE re, int term) { int options, opt; const int embeddable = ONIG_OPTION_MULTILINE|ONIG_OPTION_IGNORECASE|ONIG_OPTION_EXTEND; - long len; - const UChar* ptr; VALUE str = rb_str_buf_new2("(?"); char optbuf[OPTBUF_SIZE + 1]; /* for '-' */ rb_encoding *enc = rb_enc_get(re); @@ -575,8 +573,9 @@ rb_reg_str_with_term(VALUE re, int term) rb_enc_copy(str, re); options = RREGEXP_PTR(re)->options; - ptr = (UChar*)RREGEXP_SRC_PTR(re); - len = RREGEXP_SRC_LEN(re); + VALUE src_str = RREGEXP_SRC(re); + const UChar *ptr = (UChar *)RSTRING_PTR(src_str); + long len = RSTRING_LEN(src_str); again: if (len >= 4 && ptr[0] == '(' && ptr[1] == '?') { int err = 1; @@ -666,6 +665,8 @@ rb_reg_str_with_term(VALUE re, int term) } rb_enc_copy(str, re); + RB_GC_GUARD(src_str); + return str; } diff --git a/test/ruby/test_regexp.rb b/test/ruby/test_regexp.rb index 4d94702502..77e9ca67f6 100644 --- a/test/ruby/test_regexp.rb +++ b/test/ruby/test_regexp.rb @@ -72,6 +72,18 @@ class TestRegexp < Test::Unit::TestCase end end + def test_to_s_under_gc_compact_stress + EnvUtil.under_gc_compact_stress do + str = "abcd\u3042" + [:UTF_16BE, :UTF_16LE, :UTF_32BE, :UTF_32LE].each do |es| + enc = Encoding.const_get(es) + rs = Regexp.new(str.encode(enc)).to_s + assert_equal("(?-mix:abcd\u3042)".encode(enc), rs) + assert_equal(enc, rs.encoding) + end + end + end + def test_to_s_extended_subexp re = /#\g#{"\n"}/x re = /#{re}/