Skip to content

Commit 4289572

Browse files
committed
[Bug #22449] Fix out-of-bounds in Array#sample when array modified
Get the length after the conversion using `to_int` is complete.
1 parent 0a1c711 commit 4289572

2 files changed

Lines changed: 15 additions & 9 deletions

File tree

‎array.c‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7027,8 +7027,8 @@ ary_sample(rb_execution_context_t *ec, VALUE ary, VALUE randgen, VALUE nv, VALUE
70277027
rb_len_t rnds[numberof(idx)];
70287028
rb_len_t memo_threshold;
70297029

7030-
len = RARRAY_LEN(ary);
70317030
if (!to_array) {
7031+
len = RARRAY_LEN(ary);
70327032
if (len < 2)
70337033
i = 0;
70347034
else
@@ -7038,6 +7038,7 @@ ary_sample(rb_execution_context_t *ec, VALUE ary, VALUE randgen, VALUE nv, VALUE
70387038
}
70397039
n = NUM2LEN(nv);
70407040
if (n < 0) rb_raise(rb_eArgError, "negative sample number");
7041+
len = RARRAY_LEN(ary);
70417042
if (n > len) n = len;
70427043
if (n <= numberof(idx)) {
70437044
for (i = 0; i < n; ++i) {

‎test/ruby/test_array.rb‎

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3443,17 +3443,22 @@ def test_sample_modify_array_out_of_bounds
34433443
gen = Object.new
34443444
# 49 will be out-of-bounds when ary.replace is called
34453445
def gen.rand(lim) = 49
3446-
assert_equal([], ary.sample(obj, random: gen))
3446+
assert_raise(RangeError) {ary.sample(obj, random: gen)}
34473447

34483448
ary = (1..100).to_a
3449-
obj = Object.new
3450-
obj.define_singleton_method(:to_int) do
3451-
ary.replace(Array.new(10) { :x })
3452-
10
3453-
end
34543449
gen = Object.new
3455-
gen.define_singleton_method(:rand) { |lim| 8 }
3456-
assert_equal([], ary.sample(obj, random: gen))
3450+
def gen.rand(lim) = lim-1
3451+
assert_equal((41..50).to_a.reverse, ary.sample(obj, random: gen))
3452+
3453+
ary = (1..100).to_a
3454+
gen = Object.new
3455+
gen.define_singleton_method(:rand) do |lim|
3456+
if (lim -= 1) <= 90
3457+
ary.replace((1..50).to_a)
3458+
end
3459+
lim
3460+
end
3461+
assert_equal([], ary.sample(10, random: gen))
34573462
end
34583463

34593464
def test_cycle

0 commit comments

Comments
 (0)