summaryrefslogtreecommitdiff
path: root/gc.c
diff options
context:
space:
mode:
authorAaron Patterson <tenderlove@ruby-lang.org>2019-06-03 15:15:48 -0700
committerAaron Patterson <tenderlove@ruby-lang.org>2019-06-03 15:15:48 -0700
commitc9b74f9fd95113df903fc34cc1d6ec3fb3160c85 (patch)
tree3418ccd6497c5de25db984f2b8b906fd17eb148e /gc.c
parent790a1b17902f7ccb5939b9e0314571079fc30bc8 (diff)
Pin keys in "compare by identity" hashes
Hashes that compare by identity care about the location of the object in memory. Since they care about the memory location, we can't let them move.
Diffstat (limited to 'gc.c')
-rw-r--r--gc.c16
1 files changed, 15 insertions, 1 deletions
diff --git a/gc.c b/gc.c
index 5a94ca0b89..19ddf9bf20 100644
--- a/gc.c
+++ b/gc.c
@@ -4547,10 +4547,24 @@ mark_keyvalue(st_data_t key, st_data_t value, st_data_t data)
return ST_CONTINUE;
}
+static int
+pin_key_mark_value(st_data_t key, st_data_t value, st_data_t data)
+{
+ rb_objspace_t *objspace = (rb_objspace_t *)data;
+
+ gc_mark_and_pin(objspace, (VALUE)key);
+ gc_mark(objspace, (VALUE)value);
+ return ST_CONTINUE;
+}
+
static void
mark_hash(rb_objspace_t *objspace, VALUE hash)
{
- rb_hash_stlike_foreach(hash, mark_keyvalue, (st_data_t)objspace);
+ if (rb_hash_compare_by_id_p(hash)) {
+ rb_hash_stlike_foreach(hash, pin_key_mark_value, (st_data_t)objspace);
+ } else {
+ rb_hash_stlike_foreach(hash, mark_keyvalue, (st_data_t)objspace);
+ }
if (RHASH_AR_TABLE_P(hash)) {
if (objspace->mark_func_data == NULL && RHASH_TRANSIENT_P(hash)) {