diff --git a/ChangeLog b/ChangeLog index cb03e2df6c..6cf7a0f0eb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +Mon Dec 21 18:33:00 2015 Koichi Sasada + + * gc.c (internal_object_p): should not expose singleton classes + without a metaclass. + [Bug #11740] + + * class.c (rb_singleton_class_has_metaclass_p): added. + + * test/ruby/test_class.rb: add a test. + Mon Dec 21 12:15:32 2015 Kimura Wataru * test/ruby/test_io.rb: handled rlimit value same as r52277 diff --git a/class.c b/class.c index f95890bbc4..fdebee8933 100644 --- a/class.c +++ b/class.c @@ -442,6 +442,12 @@ rb_singleton_class_attached(VALUE klass, VALUE obj) */ #define META_CLASS_OF_CLASS_CLASS_P(k) (METACLASS_OF(k) == (k)) +int +rb_singleton_class_has_metaclass_p(VALUE sklass) +{ + return rb_attr_get(METACLASS_OF(sklass), id_attached) == sklass; +} + /*! * whether k has a metaclass * @retval 1 if \a k has a metaclass @@ -449,7 +455,13 @@ rb_singleton_class_attached(VALUE klass, VALUE obj) */ #define HAVE_METACLASS_P(k) \ (FL_TEST(METACLASS_OF(k), FL_SINGLETON) && \ - rb_ivar_get(METACLASS_OF(k), id_attached) == (k)) + rb_singleton_class_has_metaclass_p(k)) + +int +rb_class_has_metaclass_p(VALUE klass) +{ + return HAVE_METACLASS_P(klass); +} /*! * ensures \a klass belongs to its own eigenclass. diff --git a/gc.c b/gc.c index 12be1eac11..a57addf1c4 100644 --- a/gc.c +++ b/gc.c @@ -2400,6 +2400,13 @@ internal_object_p(VALUE obj) case T_NODE: case T_ZOMBIE: break; + case T_CLASS: + { + if (FL_TEST(obj, FL_SINGLETON)) { + int rb_singleton_class_has_metaclass_p(VALUE sklass); + return rb_singleton_class_has_metaclass_p(obj) == 0; + } + } default: if (!p->as.basic.klass) break; return 0; diff --git a/test/ruby/test_class.rb b/test/ruby/test_class.rb index e60db37c15..81c11e6f88 100644 --- a/test/ruby/test_class.rb +++ b/test/ruby/test_class.rb @@ -556,4 +556,24 @@ class TestClass < Test::Unit::TestCase } end; end + + def test_should_not_expose_singleton_class_without_metaclass + assert_normal_exit %q{ + klass = Class.new(Array) + # The metaclass of +klass+ should handle #bla since it should inherit methods from meta:meta:Array + def (Array.singleton_class).bla; :bla; end + hidden = ObjectSpace.each_object(Class).find { |c| klass.is_a? c and c.inspect.include? klass.inspect } + raise unless hidden.nil? + }, '[Bug #11740]' + + assert_normal_exit %q{ + klass = Class.new(Array) + klass.singleton_class + # The metaclass of +klass+ should handle #bla since it should inherit methods from meta:meta:Array + def (Array.singleton_class).bla; :bla; end + hidden = ObjectSpace.each_object(Class).find { |c| klass.is_a? c and c.inspect.include? klass.inspect } + raise if hidden.nil? + }, '[Bug #11740]' + + end end