diff options
| author | nagachika <nagachika@ruby-lang.org> | 2024-07-13 15:43:23 +0900 |
|---|---|---|
| committer | nagachika <nagachika@ruby-lang.org> | 2024-07-13 15:43:23 +0900 |
| commit | 90a44bcd39c569d851f73d167955c83f3ff2384f (patch) | |
| tree | 654c76fe344314b3ccf99c18f3149db360f48e6d | |
| parent | d802b6122b5e501cc0172376acb185160710454a (diff) | |
merge revision(s) f36a71e26995b69ff72bc132bbcf40ad89571414: [Backport #20307]
[Bug #20307] Fix `Hash#update` to make frozen copy of string keys
| -rw-r--r-- | hash.c | 14 | ||||
| -rw-r--r-- | test/ruby/test_hash.rb | 17 | ||||
| -rw-r--r-- | version.h | 2 |
3 files changed, 18 insertions, 15 deletions
@@ -3969,18 +3969,9 @@ rb_hash_invert(VALUE hash) } static int -rb_hash_update_callback(st_data_t *key, st_data_t *value, struct update_arg *arg, int existing) -{ - *value = arg->arg; - return ST_CONTINUE; -} - -NOINSERT_UPDATE_CALLBACK(rb_hash_update_callback) - -static int rb_hash_update_i(VALUE key, VALUE value, VALUE hash) { - RHASH_UPDATE(hash, key, rb_hash_update_callback, value); + rb_hash_aset(hash, key, value); return ST_CONTINUE; } @@ -3992,6 +3983,9 @@ rb_hash_update_block_callback(st_data_t *key, st_data_t *value, struct update_ar if (existing) { newvalue = (st_data_t)rb_yield_values(3, (VALUE)*key, (VALUE)*value, (VALUE)newvalue); } + else if (RHASH_STRING_KEY_P(arg->hash, *key) && !RB_OBJ_FROZEN(*key)) { + *key = rb_hash_key_str(*key); + } *value = newvalue; return ST_CONTINUE; } diff --git a/test/ruby/test_hash.rb b/test/ruby/test_hash.rb index 639c0105c0..cef9f88a3c 100644 --- a/test/ruby/test_hash.rb +++ b/test/ruby/test_hash.rb @@ -1397,6 +1397,15 @@ class TestHash < Test::Unit::TestCase assert_equal(@cls[a: 10, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8, i: 9, j: 10], h) end + def test_update_on_identhash + key = +'a' + i = @cls[].compare_by_identity + i[key] = 0 + h = @cls[].update(i) + key.upcase! + assert_equal(0, h.fetch('a')) + end + def test_merge h1 = @cls[1=>2, 3=>4] h2 = {1=>3, 5=>7} @@ -1419,10 +1428,10 @@ class TestHash < Test::Unit::TestCase expected[7] = 8 h2 = h.merge(7=>8) assert_equal(expected, h2) - assert_equal(true, h2.compare_by_identity?) + assert_predicate(h2, :compare_by_identity?) h2 = h.merge({}) assert_equal(h, h2) - assert_equal(true, h2.compare_by_identity?) + assert_predicate(h2, :compare_by_identity?) h = @cls[] h.compare_by_identity @@ -1430,10 +1439,10 @@ class TestHash < Test::Unit::TestCase h1.compare_by_identity h2 = h.merge(7=>8) assert_equal(h1, h2) - assert_equal(true, h2.compare_by_identity?) + assert_predicate(h2, :compare_by_identity?) h2 = h.merge({}) assert_equal(h, h2) - assert_equal(true, h2.compare_by_identity?) + assert_predicate(h2, :compare_by_identity?) end def test_merge! @@ -11,7 +11,7 @@ # define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR #define RUBY_VERSION_TEENY 4 #define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR -#define RUBY_PATCHLEVEL 186 +#define RUBY_PATCHLEVEL 187 #include "ruby/version.h" #include "ruby/internal/abi.h" |
