merge revision(s) 8c360ce713f57d4177de833297364f6f6d950420: [Backport #19589]

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.
	---
	 hash.c                 | 12 +++++++++---
	 test/ruby/test_hash.rb | 11 +++++++++++
	 2 files changed, 20 insertions(+), 3 deletions(-)
This commit is contained in:
nagachika 2023-07-17 14:21:39 +09:00
Родитель a7b0d3c9db
Коммит 8165db0f46
3 изменённых файлов: 21 добавлений и 4 удалений

12
hash.c
Просмотреть файл

@ -1409,13 +1409,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)
{
@ -1439,7 +1445,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);
}
@ -1457,7 +1463,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);
}
}

Просмотреть файл

@ -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]

Просмотреть файл

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