summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYusuke Endoh <mame@ruby-lang.org>2022-12-01 01:31:24 +0900
committerYusuke Endoh <mame@ruby-lang.org>2022-12-01 02:38:51 +0900
commitab4c7077cc44cd6725625562b7380a44cf462190 (patch)
tree29c92f2b67fad0b7378de21bc66a34c4b33361c5
parentf0c9d2a0c801569725459420acefc8d983bbf307 (diff)
downloadruby-ab4c7077cc44cd6725625562b7380a44cf462190.tar.gz
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]
-rw-r--r--re.c7
-rw-r--r--test/ruby/test_string.rb9
2 files changed, 16 insertions, 0 deletions
diff --git a/re.c b/re.c
index 15fe10b6af..b1c9dcd340 100644
--- a/re.c
+++ b/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);
diff --git a/test/ruby/test_string.rb b/test/ruby/test_string.rb
index 66db5b565d..1ece47b18a 100644
--- a/test/ruby/test_string.rb
+++ b/test/ruby/test_string.rb
@@ -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)