From 88bfa3005cdc58515630ad4e2b3e9f9eb09563d4 Mon Sep 17 00:00:00 2001 From: Peter Zhu Date: Tue, 22 Sep 2026 00:22:11 +0900 Subject: [PATCH] Fix buffer overflow in String#rpartition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The conversion of the pattern to string can cause the string to be modified. This can cause a buffer overflow since it uses the original length of the string. For example, the following script reports a buffer overflow with ASAN: s = "héllo" * 1000 obj = Object.new obj.define_singleton_method(:to_str) do s.replace("hé") "l" end p s.rpartition(obj) --- string.c | 6 ++++-- test/ruby/test_string.rb | 11 +++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/string.c b/string.c index c890a03222b546..4c99f8d4a548ac 100644 --- a/string.c +++ b/string.c @@ -12724,10 +12724,11 @@ rb_str_partition(VALUE str, VALUE sep) static VALUE rb_str_rpartition(VALUE str, VALUE sep) { - long pos = RSTRING_LEN(str); + long pos; sep = get_pat_quoted(sep, 0); if (RB_TYPE_P(sep, T_REGEXP)) { + pos = RSTRING_LEN(str); if (rb_reg_search(sep, str, pos, 1) < 0) { goto failed; } @@ -12737,7 +12738,8 @@ rb_str_rpartition(VALUE str, VALUE sep) sep = rb_str_subseq(str, pos, RMATCH_END(match, 0) - pos); } else { - pos = rb_str_sublen(str, pos); + /* str may have been modified by #to_str above */ + pos = rb_str_sublen(str, RSTRING_LEN(str)); pos = rb_str_rindex(str, sep, pos); if (pos < 0) { goto failed; diff --git a/test/ruby/test_string.rb b/test/ruby/test_string.rb index 8e2b3f7e9bb5fd..e4d00d5615945d 100644 --- a/test/ruby/test_string.rb +++ b/test/ruby/test_string.rb @@ -3425,6 +3425,17 @@ def (hyphen = Object.new).to_str; "-"; end assert_equal(["", "", s], s.rpartition(sep)) end + def test_rpartition_string_modified + str = S("héllo" * 1000) + replacement = S("hé") + obj = Object.new + obj.define_singleton_method(:to_str) do + str.replace(replacement) + "-" + end + assert_equal([S(""), S(""), replacement], str.rpartition(obj)) + end + def test_rs return unless @cls == String