Fix crash when replacing ST hash with AR hash
With VWA, AR hashes are much larger than ST hashes. Hash#replace attempts to directly copy the contents of AR hashes into ST hashes so there will be memory corruption caused by writing past the end of memory. This commit changes it so that if a ST hash is being replaced with an AR hash it will insert each element into the ST hash.
This commit is contained in:
parent
061e01ee50
commit
a86f798fc2
Notes:
git
2023-05-23 19:28:20 +00:00
30
hash.c
30
hash.c
@ -2906,14 +2906,38 @@ rb_hash_replace(VALUE hash, VALUE hash2)
|
||||
else {
|
||||
RHASH_ST_CLEAR(hash);
|
||||
}
|
||||
hash_copy(hash, hash2);
|
||||
|
||||
if (RHASH_AR_TABLE_P(hash2)) {
|
||||
if (RHASH_AR_TABLE_P(hash)) {
|
||||
ar_copy(hash, hash2);
|
||||
}
|
||||
else {
|
||||
st_table *tab = RHASH_ST_TABLE(hash);
|
||||
rb_st_init_existing_table_with_size(tab, &objhash, RHASH_AR_TABLE_SIZE(hash2));
|
||||
|
||||
int bound = RHASH_AR_TABLE_BOUND(hash2);
|
||||
for (int i = 0; i < bound; i++) {
|
||||
if (ar_cleared_entry(hash2, i)) continue;
|
||||
|
||||
ar_table_pair *pair = RHASH_AR_TABLE_REF(hash2, i);
|
||||
st_add_direct(tab, pair->key, pair->val);
|
||||
RB_OBJ_WRITTEN(hash, Qundef, pair->key);
|
||||
RB_OBJ_WRITTEN(hash, Qundef, pair->val);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
HASH_ASSERT(sizeof(st_table) <= sizeof(ar_table));
|
||||
|
||||
RHASH_ST_TABLE_SET(hash, st_copy(RHASH_ST_TABLE(hash2)));
|
||||
rb_gc_writebarrier_remember(hash);
|
||||
}
|
||||
|
||||
if (RHASH_EMPTY_P(hash2) && RHASH_ST_TABLE_P(hash2)) {
|
||||
/* ident hash */
|
||||
hash_st_table_init(hash, RHASH_TYPE(hash2), 0);
|
||||
}
|
||||
|
||||
rb_gc_writebarrier_remember(hash);
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
@ -179,7 +179,6 @@ static inline void
|
||||
RHASH_ST_CLEAR(VALUE h)
|
||||
{
|
||||
memset(RHASH_ST_TABLE(h), 0, sizeof(st_table));
|
||||
FL_UNSET_RAW(h, RHASH_ST_TABLE_FLAG);
|
||||
}
|
||||
|
||||
static inline unsigned
|
||||
|
@ -850,6 +850,16 @@ class TestHash < Test::Unit::TestCase
|
||||
assert(true)
|
||||
end
|
||||
|
||||
def test_replace_st_with_ar
|
||||
# ST hash
|
||||
h1 = { a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8, i: 9 }
|
||||
# AR hash
|
||||
h2 = { a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7 }
|
||||
# Replace ST hash with AR hash
|
||||
h1.replace(h2)
|
||||
assert_equal(h2, h1)
|
||||
end
|
||||
|
||||
def test_shift
|
||||
h = @h.dup
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user