summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog12
-rw-r--r--array.c4
-rw-r--r--test/ruby/test_array.rb13
-rw-r--r--version.h2
4 files changed, 25 insertions, 6 deletions
diff --git a/ChangeLog b/ChangeLog
index 19d20e7047..9ebbd84262 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+Tue Dec 27 20:02:43 2016 Kazuki Yamaguchi <k@rhe.jp>
+
+ * array.c (rb_ary_{repeated_,}combination): 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. [Bug #13052]
+
Tue Dec 27 19:57:51 2016 Nobuyoshi Nakada <nobu@ruby-lang.org>
* sprintf.c (rb_str_format): fix memory corruption by width underflow.
diff --git a/array.c b/array.c
index 28e43c68c0..1ae14edf3a 100644
--- a/array.c
+++ b/array.c
@@ -4985,7 +4985,7 @@ rb_ary_combination(VALUE ary, VALUE num)
rb_yield(rb_ary_new2(0));
}
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)));
}
}
@@ -5184,7 +5184,7 @@ rb_ary_repeated_combination(VALUE ary, VALUE num)
rb_yield(rb_ary_new2(0));
}
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)));
}
}
diff --git a/test/ruby/test_array.rb b/test/ruby/test_array.rb
index 32080bb756..3b3ad2d63d 100644
--- a/test/ruby/test_array.rb
+++ b/test/ruby/test_array.rb
@@ -2329,11 +2329,18 @@ class TestArray < Test::Unit::TestCase
def test_combination_clear
bug9939 = '[ruby-core:63149] [Bug #9939]'
- assert_separately([], <<-'end;')
- 100_000.times {Array.new(1000)}
+ assert_nothing_raised(bug9939) {
a = [*0..100]
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
def test_product2
diff --git a/version.h b/version.h
index 9e94d611ea..aa44d1325b 100644
--- a/version.h
+++ b/version.h
@@ -1,6 +1,6 @@
#define RUBY_VERSION "2.2.7"
#define RUBY_RELEASE_DATE "2016-12-27"
-#define RUBY_PATCHLEVEL 410
+#define RUBY_PATCHLEVEL 411
#define RUBY_RELEASE_YEAR 2016
#define RUBY_RELEASE_MONTH 12