1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

array.c: check array length every time after yielding

Since the Array may be modified during rb_yield(), the length before
invoking the block can't be trusted. Fix possible out-of-bounds read in
Array#combination and Array#repeated_combination.

It may better to make a defensive copy of the Array, but for now let's
follow what Array#permutation does.  [ruby-core:78738] [Bug #13052]

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@57119 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
rhe 2016-12-20 05:26:08 +00:00
parent c54ede0560
commit 647ba111ea
2 changed files with 12 additions and 5 deletions

View file

@ -5194,7 +5194,7 @@ rb_ary_combination(VALUE ary, VALUE num)
rb_yield(rb_ary_new2(0)); rb_yield(rb_ary_new2(0));
} }
else if (n == 1) { else if (n == 1) {
for (i = 0; i < len; i++) { for (i = 0; i < RARRAY_LEN(ary); i++) {
rb_yield(rb_ary_new3(1, RARRAY_AREF(ary, i))); rb_yield(rb_ary_new3(1, RARRAY_AREF(ary, i)));
} }
} }
@ -5393,7 +5393,7 @@ rb_ary_repeated_combination(VALUE ary, VALUE num)
rb_yield(rb_ary_new2(0)); rb_yield(rb_ary_new2(0));
} }
else if (n == 1) { else if (n == 1) {
for (i = 0; i < len; i++) { for (i = 0; i < RARRAY_LEN(ary); i++) {
rb_yield(rb_ary_new3(1, RARRAY_AREF(ary, i))); rb_yield(rb_ary_new3(1, RARRAY_AREF(ary, i)));
} }
} }

View file

@ -2483,11 +2483,18 @@ class TestArray < Test::Unit::TestCase
def test_combination_clear def test_combination_clear
bug9939 = '[ruby-core:63149] [Bug #9939]' bug9939 = '[ruby-core:63149] [Bug #9939]'
assert_ruby_status([], <<-'end;', bug9939) assert_nothing_raised(bug9939) {
100_000.times {Array.new(1000)}
a = [*0..100] a = [*0..100]
a.combination(3) {|*,x| a.clear} a.combination(3) {|*,x| a.clear}
end; }
bug13052 = '[ruby-core:78738] [Bug #13052] Array#combination segfaults if the Array is modified during iteration'
assert_nothing_raised(bug13052) {
a = [*0..100]
a.combination(1) { a.clear }
a = [*0..100]
a.repeated_combination(1) { a.clear }
}
end end
def test_product2 def test_product2