merge revision(s) 7793b59c8d2a13c124fe276e11723db23facce04: [Backport #21331]

[Bug #21331] Prohibit hash modification during stlike loop
This commit is contained in:
nagachika 2025-05-17 15:57:05 +09:00
parent b25bfd33e9
commit cb49400d68
3 changed files with 27 additions and 3 deletions

20
hash.c
View File

@ -1391,6 +1391,7 @@ hash_foreach_ensure(VALUE hash)
return 0;
}
/* This does not manage iteration level */
int
rb_hash_stlike_foreach(VALUE hash, st_foreach_callback_func *func, st_data_t arg)
{
@ -1402,6 +1403,7 @@ rb_hash_stlike_foreach(VALUE hash, st_foreach_callback_func *func, st_data_t arg
}
}
/* This does not manage iteration level */
int
rb_hash_stlike_foreach_with_replace(VALUE hash, st_foreach_check_callback_func *func, st_update_callback_func *replace, st_data_t arg)
{
@ -3326,6 +3328,20 @@ transform_values_foreach_replace(st_data_t *key, st_data_t *value, st_data_t arg
return ST_CONTINUE;
}
static VALUE
transform_values_call(VALUE hash)
{
rb_hash_stlike_foreach_with_replace(hash, transform_values_foreach_func, transform_values_foreach_replace, hash);
return hash;
}
static void
transform_values(VALUE hash)
{
hash_iter_lev_inc(hash);
rb_ensure(transform_values_call, hash, hash_foreach_ensure, hash);
}
/*
* call-seq:
* hash.transform_values {|value| ... } -> new_hash
@ -3356,7 +3372,7 @@ rb_hash_transform_values(VALUE hash)
SET_DEFAULT(result, Qnil);
if (!RHASH_EMPTY_P(hash)) {
rb_hash_stlike_foreach_with_replace(result, transform_values_foreach_func, transform_values_foreach_replace, result);
transform_values(result);
compact_after_delete(result);
}
@ -3385,7 +3401,7 @@ rb_hash_transform_values_bang(VALUE hash)
rb_hash_modify_check(hash);
if (!RHASH_TABLE_EMPTY_P(hash)) {
rb_hash_stlike_foreach_with_replace(hash, transform_values_foreach_func, transform_values_foreach_replace, hash);
transform_values(hash);
}
return hash;

View File

@ -1816,6 +1816,14 @@ class TestHash < Test::Unit::TestCase
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)
x = (1..1337).to_h {|k| [k, k]}
assert_raise_with_message(RuntimeError, /rehash during iteration/) do
x.transform_values! {|v|
x.rehash if v == 1337
v * 2
}
end
end
def hrec h, n, &b

View File

@ -11,7 +11,7 @@
# define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR
#define RUBY_VERSION_TEENY 8
#define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR
#define RUBY_PATCHLEVEL 148
#define RUBY_PATCHLEVEL 149
#include "ruby/version.h"
#include "ruby/internal/abi.h"