Skip to content

Commit a21b88a

Browse files
nobuk0kubun
authored andcommitted
[Bug #21331] Prohibit hash modification during stlike loop
1 parent 22f2047 commit a21b88a

File tree

2 files changed

+26
-2
lines changed

2 files changed

+26
-2
lines changed

hash.c

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1404,6 +1404,7 @@ hash_foreach_ensure(VALUE hash)
14041404
return 0;
14051405
}
14061406

1407+
/* This does not manage iteration level */
14071408
int
14081409
rb_hash_stlike_foreach(VALUE hash, st_foreach_callback_func *func, st_data_t arg)
14091410
{
@@ -1415,6 +1416,7 @@ rb_hash_stlike_foreach(VALUE hash, st_foreach_callback_func *func, st_data_t arg
14151416
}
14161417
}
14171418

1419+
/* This does not manage iteration level */
14181420
int
14191421
rb_hash_stlike_foreach_with_replace(VALUE hash, st_foreach_check_callback_func *func, st_update_callback_func *replace, st_data_t arg)
14201422
{
@@ -3312,6 +3314,20 @@ transform_values_foreach_replace(st_data_t *key, st_data_t *value, st_data_t arg
33123314
return ST_CONTINUE;
33133315
}
33143316

3317+
static VALUE
3318+
transform_values_call(VALUE hash)
3319+
{
3320+
rb_hash_stlike_foreach_with_replace(hash, transform_values_foreach_func, transform_values_foreach_replace, hash);
3321+
return hash;
3322+
}
3323+
3324+
static void
3325+
transform_values(VALUE hash)
3326+
{
3327+
hash_iter_lev_inc(hash);
3328+
rb_ensure(transform_values_call, hash, hash_foreach_ensure, hash);
3329+
}
3330+
33153331
/*
33163332
* call-seq:
33173333
* hash.transform_values {|value| ... } -> new_hash
@@ -3342,7 +3358,7 @@ rb_hash_transform_values(VALUE hash)
33423358
SET_DEFAULT(result, Qnil);
33433359

33443360
if (!RHASH_EMPTY_P(hash)) {
3345-
rb_hash_stlike_foreach_with_replace(result, transform_values_foreach_func, transform_values_foreach_replace, result);
3361+
transform_values(result);
33463362
compact_after_delete(result);
33473363
}
33483364

@@ -3371,7 +3387,7 @@ rb_hash_transform_values_bang(VALUE hash)
33713387
rb_hash_modify_check(hash);
33723388

33733389
if (!RHASH_TABLE_EMPTY_P(hash)) {
3374-
rb_hash_stlike_foreach_with_replace(hash, transform_values_foreach_func, transform_values_foreach_replace, hash);
3390+
transform_values(hash);
33753391
}
33763392

33773393
return hash;

test/ruby/test_hash.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1853,6 +1853,14 @@ def test_transform_values_bang
18531853
end
18541854
end
18551855
assert_equal(@cls[a: 2, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8, i: 9, j: 10], x)
1856+
1857+
x = (1..1337).to_h {|k| [k, k]}
1858+
assert_raise_with_message(RuntimeError, /rehash during iteration/) do
1859+
x.transform_values! {|v|
1860+
x.rehash if v == 1337
1861+
v * 2
1862+
}
1863+
end
18561864
end
18571865

18581866
def hrec h, n, &b

0 commit comments

Comments
 (0)