summaryrefslogtreecommitdiff
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
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.
-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)) {