Fix buffer overflow in Array#values_at

Array#values_at can execute arbitrary code during execution which may
modify the source array. This can cause a buffer overflow if the new length
of the array has decreased. The following script crashes:

    a = (0..100_000).to_a
    obj = Object.new
    obj.define_singleton_method(:begin) do
      a.clear
      0
    end
    obj.define_singleton_method(:end) { 10_000 }
    obj.define_singleton_method(:exclude_end?) { false }
    puts a.values_at(obj).length
This commit is contained in:
Peter Zhu committed 2026-09-17 09:01:17 +09:00
1 parent 18ac8cd1d5
commit 3f6143715a
2 files changed
+15
Notes: git 2026-09-17 00:01:47 +00:00

No files matched your search

+3
View File
@@ -3963,6 +3963,9 @@ append_values_at_single(VALUE result, VALUE ary, long olen, VALUE idx)
/* check if idx is Range */
else if (rb_range_beg_len(idx, &beg, &len, olen, 1)) {
if (len > 0) {
// rb_range_beg_len may run arbitrary code that modifies ary, so we
// need to re-calculate olen
const long olen = RARRAY_LEN(ary);
const VALUE *const src = RARRAY_CONST_PTR(ary);
const long end = beg + len;
const long prevlen = RARRAY_LEN(result);
+12
View File
@@ -2977,6 +2977,18 @@ class TestArray < Test::Unit::TestCase
assert_equal([nil], a.values_at(2**31-1))
end
def test_values_at_ary_modify
a = (0..100_000).to_a
obj = Object.new
obj.define_singleton_method(:begin) do
a.clear
0
end
obj.define_singleton_method(:end) { 10_000 }
obj.define_singleton_method(:exclude_end?) { false }
assert_equal(10_001, a.values_at(obj).length)
end
def test_select
assert_equal([0, 2], [0, 1, 2, 3].select {|x| x % 2 == 0 })
end