Skip to content

Commit 35da6f8

Browse files
committed
rb_ivar_defined: handle complex modules
It was assuming only objects can be complex.
1 parent 1f1b9b0 commit 35da6f8

File tree

2 files changed

+60
-1
lines changed

2 files changed

+60
-1
lines changed

test/ruby/test_shapes.rb

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,45 @@ class TooComplex < Hash
345345
end;
346346
end
347347

348+
def test_run_out_of_shape_instance_variable_defined
349+
assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
350+
begin;
351+
class A
352+
attr_reader :a, :b, :c, :d
353+
def initialize
354+
@a = @b = @c = @d = 1
355+
end
356+
end
357+
358+
o = Object.new
359+
i = 0
360+
while RubyVM::Shape.shapes_available > 0
361+
o.instance_variable_set(:"@i#{i}", 1)
362+
i += 1
363+
end
364+
365+
a = A.new
366+
assert_equal true, a.instance_variable_defined?(:@a)
367+
end;
368+
end
369+
370+
def test_run_out_of_shape_instance_variable_defined_on_module
371+
assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
372+
begin;
373+
o = Object.new
374+
i = 0
375+
while RubyVM::Shape.shapes_available > 0
376+
o.instance_variable_set(:"@i#{i}", 1)
377+
i += 1
378+
end
379+
380+
module A
381+
@a = @b = @c = @d = 1
382+
end
383+
384+
assert_equal true, A.instance_variable_defined?(:@a)
385+
end;
386+
end
348387
def test_run_out_of_shape_remove_instance_variable
349388
assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
350389
begin;

variable.c

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1809,7 +1809,27 @@ rb_ivar_defined(VALUE obj, ID id)
18091809
if (SPECIAL_CONST_P(obj)) return Qfalse;
18101810
if (rb_shape_obj_too_complex(obj)) {
18111811
VALUE idx;
1812-
if (!rb_st_lookup(ROBJECT_IV_HASH(obj), id, &idx)) {
1812+
st_table *table = NULL;
1813+
switch (BUILTIN_TYPE(obj)) {
1814+
case T_CLASS:
1815+
case T_MODULE:
1816+
table = (st_table *)RCLASS_IVPTR(obj);
1817+
break;
1818+
1819+
case T_OBJECT:
1820+
table = ROBJECT_IV_HASH(obj);
1821+
break;
1822+
1823+
default: {
1824+
struct gen_ivtbl *ivtbl;
1825+
if (rb_gen_ivtbl_get(obj, 0, &ivtbl)) {
1826+
table = ivtbl->as.complex.table;
1827+
}
1828+
break;
1829+
}
1830+
}
1831+
1832+
if (!table || !rb_st_lookup(table, id, &idx)) {
18131833
return Qfalse;
18141834
}
18151835

0 commit comments

Comments
 (0)