Skip to content

Commit 8c360ce

Browse files
committed
hash.c: Fix hash_iter_lev_dec corrupting shape
[Bug #19589] When decrementing `iter_lev` from `65` to `64` the flags would be corrupted, causing the shape_id to be invalid.
1 parent 7b230bc commit 8c360ce

2 files changed

Lines changed: 20 additions & 3 deletions

File tree

hash.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1367,13 +1367,19 @@ iter_lev_in_ivar_set(VALUE hash, int lev)
13671367
rb_ivar_set_internal(hash, id_hash_iter_lev, INT2FIX(lev));
13681368
}
13691369

1370-
static int
1370+
static inline int
13711371
iter_lev_in_flags(VALUE hash)
13721372
{
13731373
unsigned int u = (unsigned int)((RBASIC(hash)->flags >> RHASH_LEV_SHIFT) & RHASH_LEV_MAX);
13741374
return (int)u;
13751375
}
13761376

1377+
static inline void
1378+
iter_lev_in_flags_set(VALUE hash, int lev)
1379+
{
1380+
RBASIC(hash)->flags = ((RBASIC(hash)->flags & ~RHASH_LEV_MASK) | ((VALUE)lev << RHASH_LEV_SHIFT));
1381+
}
1382+
13771383
static int
13781384
RHASH_ITER_LEV(VALUE hash)
13791385
{
@@ -1397,7 +1403,7 @@ hash_iter_lev_inc(VALUE hash)
13971403
}
13981404
else {
13991405
lev += 1;
1400-
RBASIC(hash)->flags = ((RBASIC(hash)->flags & ~RHASH_LEV_MASK) | ((VALUE)lev << RHASH_LEV_SHIFT));
1406+
iter_lev_in_flags_set(hash, lev);
14011407
if (lev == RHASH_LEV_MAX) {
14021408
iter_lev_in_ivar_set(hash, lev);
14031409
}
@@ -1415,7 +1421,7 @@ hash_iter_lev_dec(VALUE hash)
14151421
}
14161422
else {
14171423
HASH_ASSERT(lev > 0);
1418-
RBASIC(hash)->flags = ((RBASIC(hash)->flags & ~RHASH_LEV_MASK) | ((lev-1) << RHASH_LEV_SHIFT));
1424+
iter_lev_in_flags_set(hash, lev - 1);
14191425
}
14201426
}
14211427

test/ruby/test_hash.rb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1556,6 +1556,17 @@ def test_callcc_reenter
15561556
end
15571557
end
15581558

1559+
def hash_iter_recursion(h, level)
1560+
return if level == 0
1561+
h.each_key {}
1562+
h.each_value { hash_iter_recursion(h, level - 1) }
1563+
end
1564+
1565+
def test_iterlevel_in_ivar_bug19589
1566+
h = { a: nil }
1567+
hash_iter_recursion(h, 200)
1568+
end
1569+
15591570
def test_threaded_iter_level
15601571
bug9105 = '[ruby-dev:47807] [Bug #9105]'
15611572
h = @cls[1=>2]

0 commit comments

Comments
 (0)