Skip to content

Commit 5bef757

Browse files
committed
Ensure we don't dereference fields_obj as Qundef
We rely on the GC to clear this when the GC is run on another EC than the cache.
1 parent 970b18e commit 5bef757

File tree

2 files changed

+19
-1
lines changed

2 files changed

+19
-1
lines changed

test/ruby/test_variable.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,22 @@ def test_genivar_cache_free
529529
assert_equal :new_value, str.instance_variable_get(:@x)
530530
end
531531

532+
def test_genivar_cache_invalidated_by_gc
533+
str = +"hello"
534+
str.instance_variable_set(:@x, :old_value)
535+
536+
str.instance_variable_get(:@x) # populate cache
537+
538+
Fiber.new {
539+
str.remove_instance_variable(:@x)
540+
str.instance_variable_set(:@x, :new_value)
541+
}.resume
542+
543+
GC.start
544+
545+
assert_equal :new_value, str.instance_variable_get(:@x)
546+
end
547+
532548
private
533549
def with_kwargs_11(v1:, v2:, v3:, v4:, v5:, v6:, v7:, v8:, v9:, v10:, v11:)
534550
local_variables

variable.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1273,7 +1273,7 @@ rb_obj_fields(VALUE obj, ID field_name)
12731273
generic_fields:
12741274
{
12751275
rb_execution_context_t *ec = GET_EC();
1276-
if (ec->gen_fields_cache.obj == obj && rb_imemo_fields_owner(ec->gen_fields_cache.fields_obj) == obj) {
1276+
if (ec->gen_fields_cache.obj == obj && !UNDEF_P(ec->gen_fields_cache.fields_obj) && rb_imemo_fields_owner(ec->gen_fields_cache.fields_obj) == obj) {
12771277
fields_obj = ec->gen_fields_cache.fields_obj;
12781278
RUBY_ASSERT(fields_obj == rb_obj_fields_generic_uncached(obj));
12791279
}
@@ -1309,6 +1309,8 @@ rb_free_generic_ivar(VALUE obj)
13091309
default:
13101310
generic_fields:
13111311
{
1312+
// Other EC may have stale caches, so fields_obj should be
1313+
// invalidated and the GC will replace with Qundef
13121314
rb_execution_context_t *ec = GET_EC();
13131315
if (ec->gen_fields_cache.obj == obj) {
13141316
ec->gen_fields_cache.obj = Qundef;

0 commit comments

Comments
 (0)