From 2d9ecc660eebb125c7ea60ded6fc3e1b04583d93 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 30 Jul 2022 22:34:49 +0900 Subject: [PATCH] Fix property between `ar_set()` and `ht_init()`. If GC occurs in `mrb_realloc()` in `ht_init()` called from `ar_set()`, the following inconsistency occurs: - If `h_ht_on()` is called before `mrb_realloc()`, `hash->hsh.ht` is referenced instead of `hash->hsh.ea` during GC. - If the pointer is changed by `ea_adjust()` in `ar_set()`, `hash->hsh.ea` (`hash->hsh.ht`) is referenced in GC before the change. These modifications can be resolved by changing the order of processing. However, if a `NoMemoryError` exception is raised, it is presumed that the size of the "AR" will be exceeded and the unintended state will continue. To prevent this, elements should be added after they have been converted to "HT". --- src/hash.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/hash.c b/src/hash.c index ceeb211ca..aac9ab570 100644 --- a/src/hash.c +++ b/src/hash.c @@ -294,6 +294,7 @@ static uint32_t ib_bit_to_capa(uint32_t bit); static void ht_init( mrb_state *mrb, struct RHash *h, uint32_t size, hash_entry *ea, uint32_t ea_capa, hash_table *ht, uint32_t ib_bit); +static void ht_set(mrb_state *mrb, struct RHash *h, mrb_value key, mrb_value val); static void ht_set_without_ib_adjustment( mrb_state *mrb, struct RHash *h, mrb_value key, mrb_value val); @@ -531,9 +532,8 @@ ar_set(mrb_state *mrb, struct RHash *h, mrb_value key, mrb_value val) if (ea_capa == ea_n_used) { if (size == ea_n_used) { if (size == AR_MAX_SIZE) { - hash_entry *ea = ea_adjust(mrb, ar_ea(h), &ea_capa, EA_MAX_CAPA); - ea_set(ea, ea_n_used, key, val); - ht_init(mrb, h, ++size, ea, ea_capa, NULL, IB_INIT_BIT); + ht_init(mrb, h, size, ar_ea(h), ea_capa, NULL, IB_INIT_BIT); + ht_set(mrb, h, key, val); return; } else { @@ -784,8 +784,9 @@ ht_init(mrb_state *mrb, struct RHash *h, uint32_t size, { size_t ib_byte_size = ib_byte_size_for(ib_bit); size_t ht_byte_size = sizeof(hash_table) + ib_byte_size; + ht = (hash_table*)mrb_realloc(mrb, ht, ht_byte_size); h_ht_on(h); - h_set_ht(h, (hash_table*)mrb_realloc(mrb, ht, ht_byte_size)); + h_set_ht(h, ht); ht_set_size(h, size); ht_set_ea(h, ea); ht_set_ea_capa(h, ea_capa);