Prevent segfault in String#scan with ObjectSpace.each_object

Calling `String#scan` without a block creates an incomplete MatchData
object whose `RMATCH(match)->str` is Qfalse. Usually this object is not
leaked, but it was possible to pull it by using ObjectSpace.each_object.

This change hides the internal MatchData object by using rb_obj_hide.

Fixes [Bug #19159]
This commit is contained in:
Yusuke Endoh 2022-12-01 01:31:24 +09:00
Родитель f0c9d2a0c8
Коммит ab4c7077cc
2 изменённых файлов: 16 добавлений и 0 удалений

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

@ -1739,6 +1739,13 @@ rb_reg_search_set_match(VALUE re, VALUE str, long pos, int reverse, int set_back
if (set_backref_str) {
RMATCH(match)->str = rb_str_new4(str);
}
else {
/* Note that a MatchData object with RMATCH(match)->str == 0 is incomplete!
* We need to hide the object from ObjectSpace.each_object.
* https://bugs.ruby-lang.org/issues/19159
*/
rb_obj_hide(match);
}
RMATCH(match)->regexp = re;
rb_backref_set(match);

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

@ -1601,6 +1601,15 @@ CODE
assert_equal(%w[1 2 3], S("a1 a2 a3").scan(/a\K./))
end
def test_scan_segv
bug19159 = '[Bug #19159]'
assert_nothing_raised(Exception, bug19159) do
ObjectSpace.each_object(MatchData).to_a
"".scan(//)
ObjectSpace.each_object(MatchData).to_a.inspect
end
end
def test_size
assert_equal(0, S("").size)
assert_equal(4, S("1234").size)