зеркало из https://github.com/github/ruby.git
Copy cvar table on clone
When a class with a class variable is cloned we need to also copy the cvar cache table from the original table to the clone. I found this bug while working on fixing [Bug #19379]. While this does not fix that bug directly it is still a required change to fix another bug revealed by the fix in https://github.com/ruby/ruby/pull/7265 This needs to be backported to 3.2.x and 3.1.x. Co-authored-by: Aaron Patterson <tenderlove@ruby-lang.org>
This commit is contained in:
Родитель
0ddf29f4d1
Коммит
b9e6580135
31
class.c
31
class.c
|
@ -404,6 +404,27 @@ class_init_copy_check(VALUE clone, VALUE orig)
|
|||
}
|
||||
}
|
||||
|
||||
struct cvc_table_copy_ctx {
|
||||
VALUE clone;
|
||||
struct rb_id_table * new_table;
|
||||
};
|
||||
|
||||
static enum rb_id_table_iterator_result
|
||||
cvc_table_copy(ID id, VALUE val, void *data) {
|
||||
struct cvc_table_copy_ctx *ctx = (struct cvc_table_copy_ctx *)data;
|
||||
struct rb_cvar_class_tbl_entry * orig_entry;
|
||||
orig_entry = (struct rb_cvar_class_tbl_entry *)val;
|
||||
|
||||
struct rb_cvar_class_tbl_entry *ent;
|
||||
|
||||
ent = ALLOC(struct rb_cvar_class_tbl_entry);
|
||||
ent->class_value = ctx->clone;
|
||||
ent->global_cvar_state = orig_entry->global_cvar_state;
|
||||
rb_id_table_insert(ctx->new_table, id, (VALUE)ent);
|
||||
|
||||
return ID_TABLE_CONTINUE;
|
||||
}
|
||||
|
||||
static void
|
||||
copy_tables(VALUE clone, VALUE orig)
|
||||
{
|
||||
|
@ -411,6 +432,16 @@ copy_tables(VALUE clone, VALUE orig)
|
|||
rb_free_const_table(RCLASS_CONST_TBL(clone));
|
||||
RCLASS_CONST_TBL(clone) = 0;
|
||||
}
|
||||
if (RCLASS_CVC_TBL(orig)) {
|
||||
struct rb_id_table *rb_cvc_tbl = RCLASS_CVC_TBL(orig);
|
||||
struct rb_id_table *rb_cvc_tbl_dup = rb_id_table_create(rb_id_table_size(rb_cvc_tbl));
|
||||
|
||||
struct cvc_table_copy_ctx ctx;
|
||||
ctx.clone = clone;
|
||||
ctx.new_table = rb_cvc_tbl_dup;
|
||||
rb_id_table_foreach(rb_cvc_tbl, cvc_table_copy, &ctx);
|
||||
RCLASS_CVC_TBL(clone) = rb_cvc_tbl_dup;
|
||||
}
|
||||
RCLASS_M_TBL(clone) = 0;
|
||||
if (!RB_TYPE_P(clone, T_ICLASS)) {
|
||||
st_data_t id;
|
||||
|
|
|
@ -33,6 +33,12 @@ class TestVariable < Test::Unit::TestCase
|
|||
end
|
||||
end
|
||||
|
||||
Athena = Gods.clone
|
||||
|
||||
def test_cloned_classes_copy_cvar_cache
|
||||
assert_equal "Cronus", Athena.new.ruler0
|
||||
end
|
||||
|
||||
def test_setting_class_variable_on_module_through_inheritance
|
||||
mod = Module.new
|
||||
mod.class_variable_set(:@@foo, 1)
|
||||
|
|
Загрузка…
Ссылка в новой задаче