summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYusuke Endoh <mame@ruby-lang.org>2023-11-08 17:09:33 +0900
committerYusuke Endoh <mame@ruby-lang.org>2023-11-21 15:15:23 +0900
commita787e0d6494443cfd9bd05ac746704079dcfd03f (patch)
treefe4769153f7e52dcd20dc13556dc1511c31b8a22
parentc3ab946e86134e05a81c0587ef1d5cdf1de4492f (diff)
Raise an exception if ar_table is converted to st_table during iteration
ar_table may be converted to st_table by `ar_force_convert_table`. If the conversion occurs during the iteration of ar_table, the iteration may lead to memory corruption. This change prevents the catastrophy by throwing an exception when the conversion is detected. This issue is reported by [SuperS](https://hackerone.com/superss)
-rw-r--r--hash.c11
1 files changed, 11 insertions, 0 deletions
diff --git a/hash.c b/hash.c
index e8613339ba..83b9e9ce66 100644
--- a/hash.c
+++ b/hash.c
@@ -811,6 +811,14 @@ ar_add_direct_with_hash(VALUE hash, st_data_t key, st_data_t val, st_hash_t hash
}
}
+static void
+ensure_ar_table(VALUE hash)
+{
+ if (!RHASH_AR_TABLE_P(hash)) {
+ rb_raise(rb_eRuntimeError, "hash representation was changed during iteration");
+ }
+}
+
static int
ar_general_foreach(VALUE hash, st_foreach_check_callback_func *func, st_update_callback_func *replace, st_data_t arg)
{
@@ -822,6 +830,7 @@ ar_general_foreach(VALUE hash, st_foreach_check_callback_func *func, st_update_c
ar_table_pair *pair = RHASH_AR_TABLE_REF(hash, i);
enum st_retval retval = (*func)(pair->key, pair->val, arg, 0);
+ ensure_ar_table(hash);
/* pair may be not valid here because of theap */
switch (retval) {
@@ -896,6 +905,7 @@ ar_foreach_check(VALUE hash, st_foreach_check_callback_func *func, st_data_t arg
hint = ar_hint(hash, i);
retval = (*func)(key, pair->val, arg, 0);
+ ensure_ar_table(hash);
hash_verify(hash);
switch (retval) {
@@ -956,6 +966,7 @@ ar_update(VALUE hash, st_data_t key,
old_key = key;
retval = (*func)(&key, &value, arg, existing);
/* pair can be invalid here because of theap */
+ ensure_ar_table(hash);
switch (retval) {
case ST_CONTINUE: