Don't create T_MATCH object if /regexp/.match(string) doesn't match

Fixes [Bug #20104]
This commit is contained in:
Luke Gruber 2023-12-30 13:26:59 -05:00 коммит произвёл Jeremy Evans
Родитель 676748abca
Коммит e12d4c654e
3 изменённых файлов: 26 добавлений и 3 удалений

9
re.c
Просмотреть файл

@ -1747,15 +1747,18 @@ rb_reg_search_set_match(VALUE re, VALUE str, long pos, int reverse, int set_back
.range = reverse ? 0 : len,
};
VALUE match = match_alloc(rb_cMatch);
struct re_registers *regs = RMATCH_REGS(match);
struct re_registers regs = {0};
OnigPosition result = rb_reg_onig_match(re, str, reg_onig_search, &args, regs);
OnigPosition result = rb_reg_onig_match(re, str, reg_onig_search, &args, &regs);
if (result == ONIG_MISMATCH) {
rb_backref_set(Qnil);
return ONIG_MISMATCH;
}
VALUE match = match_alloc(rb_cMatch);
rb_matchext_t *rm = RMATCH_EXT(match);
rm->regs = regs;
if (set_backref_str) {
RB_OBJ_WRITE(match, &RMATCH(match)->str, rb_str_new4(str));
}

Просмотреть файл

@ -711,6 +711,18 @@ class TestRegexp < Test::Unit::TestCase
}
end
def test_match_no_match_no_matchdata
EnvUtil.without_gc do
h = {}
ObjectSpace.count_objects(h)
prev_matches = h[:T_MATCH] || 0
md = /[A-Z]/.match('1') # no match
ObjectSpace.count_objects(h)
new_matches = h[:T_MATCH] || 0
assert_equal prev_matches, new_matches, "Bug [#20104]"
end
end
def test_initialize
assert_raise(ArgumentError) { Regexp.new }
assert_equal(/foo/, assert_warning(/ignored/) {Regexp.new(/foo/, Regexp::IGNORECASE)})

Просмотреть файл

@ -254,6 +254,14 @@ module EnvUtil
end
module_function :under_gc_compact_stress
def without_gc
prev_disabled = GC.disable
yield
ensure
GC.enable unless prev_disabled
end
module_function :without_gc
def with_default_external(enc)
suppress_warning { Encoding.default_external = enc }
yield