Skip to content

Commit 7793b59

Browse files
committed
[Bug #21331] Prohibit hash modification during stlike loop
1 parent 7f5b4fb commit 7793b59

2 files changed

Lines changed: 26 additions & 2 deletions

File tree

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
{
@@ -3486,6 +3488,20 @@ transform_values_foreach_replace(st_data_t *key, st_data_t *value, st_data_t arg
34863488
return ST_CONTINUE;
34873489
}
34883490

3491+
static VALUE
3492+
transform_values_call(VALUE hash)
3493+
{
3494+
rb_hash_stlike_foreach_with_replace(hash, transform_values_foreach_func, transform_values_foreach_replace, hash);
3495+
return hash;
3496+
}
3497+
3498+
static void
3499+
transform_values(VALUE hash)
3500+
{
3501+
hash_iter_lev_inc(hash);
3502+
rb_ensure(transform_values_call, hash, hash_foreach_ensure, hash);
3503+
}
3504+
34893505
/*
34903506
* call-seq:
34913507
* transform_values {|value| ... } -> new_hash
@@ -3514,7 +3530,7 @@ rb_hash_transform_values(VALUE hash)
35143530
SET_DEFAULT(result, Qnil);
35153531

35163532
if (!RHASH_EMPTY_P(hash)) {
3517-
rb_hash_stlike_foreach_with_replace(result, transform_values_foreach_func, transform_values_foreach_replace, result);
3533+
transform_values(result);
35183534
compact_after_delete(result);
35193535
}
35203536

@@ -3549,7 +3565,7 @@ rb_hash_transform_values_bang(VALUE hash)
35493565
rb_hash_modify_check(hash);
35503566

35513567
if (!RHASH_TABLE_EMPTY_P(hash)) {
3552-
rb_hash_stlike_foreach_with_replace(hash, transform_values_foreach_func, transform_values_foreach_replace, hash);
3568+
transform_values(hash);
35533569
}
35543570

35553571
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)