ruby-changes:66309
From: nagachika <ko1@a...>
Date: Sun, 23 May 2021 16:09:46 +0900 (JST)
Subject: [ruby-changes:66309] 44b87adc07 (ruby_3_0): merge revision(s) e019dd24df4ed7063ad80d4c2e4070141793f598,7954bb056be30e86c419fe3792064d28990a4999,7d3fdfb27dac456827b004d9e66a44b15f8cd762: [Backport #17736]
https://git.ruby-lang.org/ruby.git/commit/?id=44b87adc07 From 44b87adc07621b6a8eddfcf4aaff34ce634179d4 Mon Sep 17 00:00:00 2001 From: nagachika <nagachika@r...> Date: Sun, 23 May 2021 15:51:10 +0900 Subject: merge revision(s) e019dd24df4ed7063ad80d4c2e4070141793f598,7954bb056be30e86c419fe3792064d28990a4999,7d3fdfb27dac456827b004d9e66a44b15f8cd762: [Backport #17736] Ensure the receiver is modifiable before shrinking [Bug #17736] * Ensure the receiver is modifiable before shinking [Bug #17736] * Assert the receivers are not modified --- array.c | 1 + test/ruby/test_array.rb | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) Some Hash destructive methods ensure the receiver modifiable [Bug #17736] refs: * https://bugs.ruby-lang.org/issues/17736 * https://github.com/ruby/ruby/pull/4296 This commit aims to cover following methods * Hash#select! * Hash#filter! * Hash#keep_if * Hash#reject! * Hash#delete_if I think these are not all. --- * Ensure the receiver is modifiable or not * Assert the receiver is not modified --- hash.c | 2 ++ test/ruby/test_hash.rb | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) Hash#transform_values! ensures receiver modifiable in block [Bug #17736] --- hash.c | 1 + test/ruby/test_hash.rb | 9 +++++++++ 2 files changed, 10 insertions(+) --- array.c | 1 + hash.c | 3 +++ test/ruby/test_array.rb | 36 ++++++++++++++++++++++++++++++++++ test/ruby/test_hash.rb | 51 +++++++++++++++++++++++++++++++++++++++++++++++++ version.h | 2 +- 5 files changed, 92 insertions(+), 1 deletion(-) diff --git a/array.c b/array.c index ea84473..c0c8016 100644 --- a/array.c +++ b/array.c @@ -3838,6 +3838,7 @@ select_bang_ensure(VALUE a) https://github.com/ruby/ruby/blob/trunk/array.c#L3838 if (i2 < len && i2 < i1) { long tail = 0; + rb_ary_modify(ary); if (i1 < len) { tail = len - i1; RARRAY_PTR_USE_TRANSIENT(ary, ptr, { diff --git a/hash.c b/hash.c index e29e985..b79f4f8 100644 --- a/hash.c +++ b/hash.c @@ -2476,6 +2476,7 @@ static int https://github.com/ruby/ruby/blob/trunk/hash.c#L2476 delete_if_i(VALUE key, VALUE value, VALUE hash) { if (RTEST(rb_yield_values(2, key, value))) { + rb_hash_modify(hash); return ST_DELETE; } return ST_CONTINUE; @@ -2753,6 +2754,7 @@ static int https://github.com/ruby/ruby/blob/trunk/hash.c#L2754 keep_if_i(VALUE key, VALUE value, VALUE hash) { if (!RTEST(rb_yield_values(2, key, value))) { + rb_hash_modify(hash); return ST_DELETE; } return ST_CONTINUE; @@ -3322,6 +3324,7 @@ transform_values_foreach_replace(st_data_t *key, st_data_t *value, st_data_t arg https://github.com/ruby/ruby/blob/trunk/hash.c#L3324 { VALUE new_value = rb_yield((VALUE)*value); VALUE hash = (VALUE)argp; + rb_hash_modify(hash); RB_OBJ_WRITE(hash, value, new_value); return ST_CONTINUE; } diff --git a/test/ruby/test_array.rb b/test/ruby/test_array.rb index 522b58e..789531f 100644 --- a/test/ruby/test_array.rb +++ b/test/ruby/test_array.rb @@ -754,6 +754,15 @@ class TestArray < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_array.rb#L754 a = @cls[ 5, 6, 7, 8, 9, 10 ] assert_equal(9, a.delete_if {|i| break i if i > 8; i < 7}) assert_equal(@cls[7, 8, 9, 10], a, bug2545) + + assert_raise(FrozenError) do + a = @cls[1, 2, 3, 42] + a.delete_if do + a.freeze + true + end + end + assert_equal(@cls[1, 2, 3, 42], a) end def test_dup @@ -1322,6 +1331,15 @@ class TestArray < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_array.rb#L1331 a = @cls[ 5, 6, 7, 8, 9, 10 ] assert_equal(9, a.reject! {|i| break i if i > 8; i < 7}) assert_equal(@cls[7, 8, 9, 10], a, bug2545) + + assert_raise(FrozenError) do + a = @cls[1, 2, 3, 42] + a.reject! do + a.freeze + true + end + end + assert_equal(@cls[1, 2, 3, 42], a) end def test_shared_array_reject! @@ -2599,6 +2617,15 @@ class TestArray < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_array.rb#L2617 a = @cls[ 1, 2, 3, 4, 5 ] a.select! {|i| a.clear if i == 5; false } assert_equal(0, a.size, bug13053) + + assert_raise(FrozenError) do + a = @cls[1, 2, 3, 42] + a.select! do + a.freeze + false + end + end + assert_equal(@cls[1, 2, 3, 42], a) end # also select! @@ -2614,6 +2641,15 @@ class TestArray < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_array.rb#L2641 a = @cls[ 1, 2, 3, 4, 5 ] assert_equal(a, a.keep_if { |i| i > 3 }) assert_equal(@cls[4, 5], a) + + assert_raise(FrozenError) do + a = @cls[1, 2, 3, 42] + a.keep_if do + a.freeze + false + end + end + assert_equal(@cls[1, 2, 3, 42], a) end def test_filter diff --git a/test/ruby/test_hash.rb b/test/ruby/test_hash.rb index 812b9e6..aaf92d4 100644 --- a/test/ruby/test_hash.rb +++ b/test/ruby/test_hash.rb @@ -419,6 +419,15 @@ class TestHash < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_hash.rb#L419 true } assert_equal(base.size, n) + + h = base.dup + assert_raise(FrozenError) do + h.delete_if do + h.freeze + true + end + end + assert_equal(base.dup, h) end def test_keep_if @@ -426,6 +435,14 @@ class TestHash < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_hash.rb#L435 assert_equal({3=>4,5=>6}, h.keep_if {|k, v| k + v >= 7 }) h = @cls[1=>2,3=>4,5=>6] assert_equal({1=>2,3=>4,5=>6}, h.keep_if{true}) + h = @cls[1=>2,3=>4,5=>6] + assert_raise(FrozenError) do + h.keep_if do + h.freeze + false + end + end + assert_equal(@cls[1=>2,3=>4,5=>6], h) end def test_compact @@ -722,6 +739,15 @@ class TestHash < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_hash.rb#L739 h = base.dup assert_equal(h3, h.reject! {|k,v| v }) assert_equal(h3, h) + + h = base.dup + assert_raise(FrozenError) do + h.reject! do + h.freeze + true + end + end + assert_equal(base.dup, h) end def test_replace @@ -1025,6 +1051,14 @@ class TestHash < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_hash.rb#L1051 assert_equal({3=>4,5=>6}, h) h = @cls[1=>2,3=>4,5=>6] assert_equal(nil, h.select!{true}) + h = @cls[1=>2,3=>4,5=>6] + assert_raise(FrozenError) do + h.select! do + h.freeze + false + end + end + assert_equal(@cls[1=>2,3=>4,5=>6], h) end def test_slice @@ -1077,6 +1111,14 @@ class TestHash < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_hash.rb#L1111 assert_equal({3=>4,5=>6}, h) h = @cls[1=>2,3=>4,5=>6] assert_equal(nil, h.filter!{true}) + h = @cls[1=>2,3=>4,5=>6] + assert_raise(FrozenError) do + h.filter! do + h.freeze + false + end + end + assert_equal(@cls[1=>2,3=>4,5=>6], h) end def test_clear2 @@ -1720,6 +1762,15 @@ class TestHash < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_hash.rb#L1762 x = @cls[a: 1, b: 2, c: 3] y = x.transform_values!.with_index {|v, i| "#{v}.#{i}" } assert_equal(%w(1.0 2.1 3.2), y.values_at(:a, :b, :c)) + + x = @cls[a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8, i: 9, j: 10] + assert_raise(FrozenError) do + x.transform_values!() do |v| + x.freeze if v == 2 + v.succ + end + end + assert_equal(@cls[a: 2, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8, i: 9, j: 10], x) end def test_broken_hash_value diff --git a/version.h b/version.h index 36d0caa..de064cc 100644 --- a/version.h +++ b/version.h @@ -12,7 +12,7 @@ https://github.com/ruby/ruby/blob/trunk/version.h#L12 # define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR #define RUBY_VERSION_TEENY 2 #define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR -#define RUBY_PATCHLEVEL 86 +#define RUBY_PATCHLEVEL 87 #define RUBY_RELEASE_YEAR 2021 #define RUBY_RELEASE_MONTH 5 -- cgit v1.1 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/