diff options
author | Koichi Sasada <ko1@atdot.net> | 2020-03-07 03:32:15 +0900 |
---|---|---|
committer | Koichi Sasada <ko1@atdot.net> | 2020-03-07 03:34:17 +0900 |
commit | 4c019f5a626523e99e2827ed917802e3097c380d (patch) | |
tree | d3876652cd807713b18163b76940453823b8ca3f /hash.c | |
parent | 44462d32068235ccfcb892c9dde7451e5a0ad7c5 (diff) |
check ar_table after `#hash` call
ar_table can be converted to st_table just after `ar_do_hash()`
function which calls `#hash` method. We need to check
the representation to detect this mutation.
[Bug #16676]
Diffstat (limited to 'hash.c')
-rw-r--r-- | hash.c | 18 |
1 files changed, 18 insertions, 0 deletions
@@ -1012,6 +1012,11 @@ ar_update(VALUE hash, st_data_t key, st_data_t value = 0, old_key; st_hash_t hash_value = ar_do_hash(key); + if (UNLIKELY(!RHASH_AR_TABLE_P(hash))) { + // `#hash` changes ar_table -> st_table + return -1; + } + if (RHASH_AR_TABLE_SIZE(hash) > 0) { bin = ar_find_entry(hash, hash_value, key); existing = (bin != RHASH_AR_TABLE_MAX_BOUND) ? TRUE : FALSE; @@ -1061,6 +1066,11 @@ ar_insert(VALUE hash, st_data_t key, st_data_t value) unsigned bin = RHASH_AR_TABLE_BOUND(hash); st_hash_t hash_value = ar_do_hash(key); + if (UNLIKELY(!RHASH_AR_TABLE_P(hash))) { + // `#hash` changes ar_table -> st_table + return -1; + } + hash_ar_table(hash); /* prepare ltbl */ bin = ar_find_entry(hash, hash_value, key); @@ -1093,6 +1103,10 @@ ar_lookup(VALUE hash, st_data_t key, st_data_t *value) } else { st_hash_t hash_value = ar_do_hash(key); + if (UNLIKELY(!RHASH_AR_TABLE_P(hash))) { + // `#hash` changes ar_table -> st_table + return st_lookup(RHASH_ST_TABLE(hash), key, value); + } unsigned bin = ar_find_entry(hash, hash_value, key); if (bin == RHASH_AR_TABLE_MAX_BOUND) { @@ -1114,6 +1128,10 @@ ar_delete(VALUE hash, st_data_t *key, st_data_t *value) unsigned bin; st_hash_t hash_value = ar_do_hash(*key); + if (UNLIKELY(!RHASH_AR_TABLE_P(hash))) { + // `#hash` changes ar_table -> st_table + return st_delete(RHASH_ST_TABLE(hash), key, value); + } bin = ar_find_entry(hash, hash_value, *key); |