From 39cf3c0a381399f8bf4c7eda89af1caae33078e6 Mon Sep 17 00:00:00 2001 From: Kazuki Yamaguchi Date: Wed, 16 Nov 2016 19:52:02 +0900 Subject: re.c: fix for RMatch::regexp == Qnil So, don't blindly assume RMatch::regexp contains an instance of Regexp and do check properly, because it may be nil as of r45451. --- re.c | 31 ++++++++++++++++++++----------- test/ruby/test_regexp.rb | 22 +++++++++++++++++++--- 2 files changed, 39 insertions(+), 14 deletions(-) diff --git a/re.c b/re.c index 069a9bc15d..1e576d7c58 100644 --- a/re.c +++ b/re.c @@ -1088,8 +1088,7 @@ match_regexp(VALUE match) static VALUE match_names(VALUE match) { - match_check(match); - return rb_reg_names(RMATCH(match)->regexp); + return rb_reg_names(match_regexp(match)); } /* @@ -1116,9 +1115,8 @@ match_backref_number(VALUE match, VALUE backref) { const char *name; int num; - struct re_registers *regs = RMATCH_REGS(match); - VALUE regexp = RMATCH(match)->regexp; + VALUE regexp; match_check(match); switch (TYPE(backref)) { @@ -1134,6 +1132,7 @@ match_backref_number(VALUE match, VALUE backref) break; } + regexp = match_regexp(match); num = onig_name_to_backref_number(RREGEXP_PTR(regexp), (const unsigned char*)name, (const unsigned char*)name + strlen(name), @@ -1918,7 +1917,7 @@ match_ary_aref(VALUE match, VALUE idx, VALUE result) static VALUE match_aref(int argc, VALUE *argv, VALUE match) { - VALUE idx, length; + VALUE idx, length, regexp; match_check(match); rb_scan_args(argc, argv, "11", &idx, &length); @@ -1928,7 +1927,9 @@ match_aref(int argc, VALUE *argv, VALUE match) return rb_reg_nth_match(FIX2INT(idx), match); } else { - int num = namev_to_backref_number(RMATCH_REGS(match), RMATCH(match)->regexp, idx); + int num; + regexp = match_regexp(match); + num = namev_to_backref_number(RMATCH_REGS(match), regexp, idx); if (num >= 0) { return rb_reg_nth_match(num, match); } @@ -1989,7 +1990,8 @@ match_values_at(int argc, VALUE *argv, VALUE match) rb_ary_push(result, rb_reg_nth_match(FIX2INT(argv[i]), match)); } else { - int num = namev_to_backref_number(RMATCH_REGS(match), RMATCH(match)->regexp, argv[i]); + VALUE regexp = match_regexp(match); + int num = namev_to_backref_number(RMATCH_REGS(match), regexp, argv[i]); if (num >= 0) { rb_ary_push(result, rb_reg_nth_match(num, match)); } @@ -2078,15 +2080,16 @@ match_named_captures_iter(const OnigUChar *name, const OnigUChar *name_end, static VALUE match_named_captures(VALUE match) { - VALUE hash; + VALUE hash, regexp; struct MEMO *memo; match_check(match); + regexp = match_regexp(match); hash = rb_hash_new(); memo = MEMO_NEW(hash, match, 0); - onig_foreach_name(RREGEXP(RMATCH(match)->regexp)->ptr, match_named_captures_iter, (void*)memo); + onig_foreach_name(RREGEXP(regexp)->ptr, match_named_captures_iter, (void*)memo); return hash; } @@ -2947,12 +2950,14 @@ rb_reg_equal(VALUE re1, VALUE re2) static VALUE match_hash(VALUE match) { + VALUE regexp; const struct re_registers *regs; st_index_t hashval; match_check(match); + regexp = match_regexp(match); hashval = rb_hash_start(rb_str_hash(RMATCH(match)->str)); - hashval = rb_hash_uint(hashval, reg_hash(RMATCH(match)->regexp)); + hashval = rb_hash_uint(hashval, reg_hash(regexp)); regs = RMATCH_REGS(match); hashval = rb_hash_uint(hashval, regs->num_regs); hashval = rb_hash_uint(hashval, rb_memhash(regs->beg, regs->num_regs * sizeof(*regs->beg))); @@ -2974,11 +2979,15 @@ static VALUE match_equal(VALUE match1, VALUE match2) { const struct re_registers *regs1, *regs2; + VALUE reg1, reg2; + if (match1 == match2) return Qtrue; if (!RB_TYPE_P(match2, T_MATCH)) return Qfalse; if (!RMATCH(match1)->regexp || !RMATCH(match2)->regexp) return Qfalse; if (!rb_str_equal(RMATCH(match1)->str, RMATCH(match2)->str)) return Qfalse; - if (!rb_reg_equal(RMATCH(match1)->regexp, RMATCH(match2)->regexp)) return Qfalse; + reg1 = match_regexp(match1); + reg2 = match_regexp(match2); + if (!rb_reg_equal(reg1, reg2)) return Qfalse; regs1 = RMATCH_REGS(match1); regs2 = RMATCH_REGS(match2); if (regs1->num_regs != regs2->num_regs) return Qfalse; diff --git a/test/ruby/test_regexp.rb b/test/ruby/test_regexp.rb index b0da247f4f..7c09467014 100644 --- a/test/ruby/test_regexp.rb +++ b/test/ruby/test_regexp.rb @@ -639,14 +639,30 @@ class TestRegexp < Test::Unit::TestCase end def test_match_without_regexp + # create a MatchData for each assertion because the internal state may change + test = proc {|&blk| "abc".sub("a", ""); blk.call($~) } + bug10877 = '[ruby-core:68209] [Bug #10877]' - "abc".sub("a", "") - assert_raise_with_message(IndexError, /foo/, bug10877) {$~["foo"]} + test.call {|m| assert_raise_with_message(IndexError, /foo/, bug10877) {m["foo"]} } key = "\u{3042}" [Encoding::UTF_8, Encoding::Shift_JIS, Encoding::EUC_JP].each do |enc| idx = key.encode(enc) - assert_raise_with_message(IndexError, /#{idx}/, bug10877) {$~[idx]} + test.call {|m| assert_raise_with_message(IndexError, /#{idx}/, bug10877) {m[idx]} } end + test.call {|m| assert_equal(/a/, m.regexp) } + test.call {|m| assert_equal("abc", m.string) } + test.call {|m| assert_equal(1, m.size) } + test.call {|m| assert_equal(0, m.begin(0)) } + test.call {|m| assert_equal(1, m.end(0)) } + test.call {|m| assert_equal([0, 1], m.offset(0)) } + test.call {|m| assert_equal([], m.captures) } + test.call {|m| assert_equal([], m.names) } + test.call {|m| assert_equal({}, m.named_captures) } + test.call {|m| assert_equal(/a/.match("abc"), m) } + test.call {|m| assert_equal(/a/.match("abc").hash, m.hash) } + test.call {|m| assert_equal("bc", m.post_match) } + test.call {|m| assert_equal("", m.pre_match) } + test.call {|m| assert_equal(["a", nil], m.values_at(0, 1)) } end def test_last_match -- cgit v1.2.3