aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--hash.c12
-rw-r--r--test/ruby/test_hash.rb11
2 files changed, 20 insertions, 3 deletions
diff --git a/hash.c b/hash.c
index fc214cce54..32c660a210 100644
--- a/hash.c
+++ b/hash.c
@@ -1367,13 +1367,19 @@ iter_lev_in_ivar_set(VALUE hash, int lev)
rb_ivar_set_internal(hash, id_hash_iter_lev, INT2FIX(lev));
}
-static int
+static inline int
iter_lev_in_flags(VALUE hash)
{
unsigned int u = (unsigned int)((RBASIC(hash)->flags >> RHASH_LEV_SHIFT) & RHASH_LEV_MAX);
return (int)u;
}
+static inline void
+iter_lev_in_flags_set(VALUE hash, int lev)
+{
+ RBASIC(hash)->flags = ((RBASIC(hash)->flags & ~RHASH_LEV_MASK) | ((VALUE)lev << RHASH_LEV_SHIFT));
+}
+
static int
RHASH_ITER_LEV(VALUE hash)
{
@@ -1397,7 +1403,7 @@ hash_iter_lev_inc(VALUE hash)
}
else {
lev += 1;
- RBASIC(hash)->flags = ((RBASIC(hash)->flags & ~RHASH_LEV_MASK) | ((VALUE)lev << RHASH_LEV_SHIFT));
+ iter_lev_in_flags_set(hash, lev);
if (lev == RHASH_LEV_MAX) {
iter_lev_in_ivar_set(hash, lev);
}
@@ -1415,7 +1421,7 @@ hash_iter_lev_dec(VALUE hash)
}
else {
HASH_ASSERT(lev > 0);
- RBASIC(hash)->flags = ((RBASIC(hash)->flags & ~RHASH_LEV_MASK) | ((lev-1) << RHASH_LEV_SHIFT));
+ iter_lev_in_flags_set(hash, lev - 1);
}
}
diff --git a/test/ruby/test_hash.rb b/test/ruby/test_hash.rb
index 83d16d462e..8b6065146c 100644
--- a/test/ruby/test_hash.rb
+++ b/test/ruby/test_hash.rb
@@ -1556,6 +1556,17 @@ class TestHash < Test::Unit::TestCase
end
end
+ def hash_iter_recursion(h, level)
+ return if level == 0
+ h.each_key {}
+ h.each_value { hash_iter_recursion(h, level - 1) }
+ end
+
+ def test_iterlevel_in_ivar_bug19589
+ h = { a: nil }
+ hash_iter_recursion(h, 200)
+ end
+
def test_threaded_iter_level
bug9105 = '[ruby-dev:47807] [Bug #9105]'
h = @cls[1=>2]