From b9e6580135d20cf3fff2e872b3e54c08e96468cb Mon Sep 17 00:00:00 2001 From: eileencodes Date: Wed, 8 Feb 2023 15:27:28 -0500 Subject: 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 --- class.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'class.c') diff --git a/class.c b/class.c index 333a9d78e5..cf1731c1ab 100644 --- a/class.c +++ b/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; -- cgit v1.2.1