Consider modified modules initialized [Bug #18185]

This commit is contained in:
Nobuyoshi Nakada 2021-09-24 00:55:11 +09:00
Родитель 854fe9d1c1
Коммит 65285bf673
4 изменённых файлов: 40 добавлений и 4 удалений

14
class.c
Просмотреть файл

@ -357,6 +357,15 @@ RMODULE_UNINITIALIZED(VALUE module)
return RCLASS_SUPER(module) == rb_cBasicObject;
}
void
rb_module_set_initialized(VALUE mod)
{
if (RMODULE_UNINITIALIZED(mod)) {
RB_OBJ_WRITE(mod, &RCLASS(mod)->super, 0);
/* no more re-initialization */
}
}
void
rb_module_check_initializable(VALUE mod)
{
@ -916,10 +925,7 @@ ensure_includable(VALUE klass, VALUE module)
{
rb_class_modify_check(klass);
Check_Type(module, T_MODULE);
if (RMODULE_UNINITIALIZED(module)) {
RB_OBJ_WRITE(module, &RCLASS(module)->super, 0);
/* no more re-initialization */
}
rb_module_set_initialized(module);
if (!NIL_P(rb_refinement_module_get_refined_class(module))) {
rb_raise(rb_eArgError, "refinement module is not allowed");
}

3
eval.c
Просмотреть файл

@ -424,6 +424,9 @@ rb_class_modify_check(VALUE klass)
if (SPECIAL_CONST_P(klass)) {
Check_Type(klass, T_CLASS);
}
if (RB_TYPE_P(klass, T_MODULE)) {
rb_module_set_initialized(klass);
}
if (OBJ_FROZEN(klass)) {
const char *desc;

Просмотреть файл

@ -115,6 +115,7 @@ int rb_singleton_class_internal_p(VALUE sklass);
VALUE rb_class_boot(VALUE);
VALUE rb_class_s_alloc(VALUE klass);
VALUE rb_module_s_alloc(VALUE klass);
void rb_module_set_initialized(VALUE module);
void rb_module_check_initializable(VALUE module);
VALUE rb_make_metaclass(VALUE, VALUE);
VALUE rb_include_class_new(VALUE, VALUE);

Просмотреть файл

@ -446,6 +446,32 @@ class TestModule < Test::Unit::TestCase
end
end
class Bug18185 < Module
module InstanceMethods
end
def initialize
include InstanceMethods
end
class Foo
attr_reader :key
def initialize(key:)
@key = key
end
end
end
def test_module_subclass_initialize
mod = Bug18185.new
c = Class.new(Bug18185::Foo) do
include mod
end
anc = c.ancestors
assert_include(anc, mod)
assert_equal(1, anc.count(BasicObject), ->{anc.inspect})
b = c.new(key: 1)
assert_equal(1, b.key)
end
def test_dup
OtherSetup.call