aboutsummaryrefslogtreecommitdiffstats
path: root/object.c
diff options
context:
space:
mode:
authorJean Boussier <byroot@ruby-lang.org>2023-10-30 12:29:59 +0100
committerPeter Zhu <peter@peterzhu.ca>2023-10-31 12:07:54 -0400
commit4aacc559d99988f395eced3534c7a6938bd356c8 (patch)
treea33af6b2ae7ae803053dad304687b321cdd73e93 /object.c
parent85ad1025328989bb4e10436aed121b9136b0c8bf (diff)
downloadruby-4aacc559d99988f395eced3534c7a6938bd356c8.tar.gz
Handle running out of shapes in `Object#dup`
There is a handful of call sites where we may transition to OBJ_TOO_COMPLEX_SHAPE if we just ran out of shapes, but that weren't handling it properly.
Diffstat (limited to 'object.c')
-rw-r--r--object.c11
1 files changed, 10 insertions, 1 deletions
diff --git a/object.c b/object.c
index 5cb0e0a650..73fbe78edc 100644
--- a/object.c
+++ b/object.c
@@ -326,9 +326,18 @@ rb_obj_copy_ivar(VALUE dest, VALUE obj)
RUBY_ASSERT(initial_shape->type == SHAPE_T_OBJECT);
shape_to_set_on_dest = rb_shape_rebuild_shape(initial_shape, src_shape);
+ if (UNLIKELY(rb_shape_id(shape_to_set_on_dest) == OBJ_TOO_COMPLEX_SHAPE_ID)) {
+ st_table * table = rb_st_init_numtable_with_size(src_num_ivs);
+
+ rb_ivar_foreach(obj, rb_obj_evacuate_ivs_to_hash_table, (st_data_t)table);
+ rb_shape_set_too_complex(dest);
+ ROBJECT(dest)->as.heap.ivptr = (VALUE *)table;
+
+ return;
+ }
}
- RUBY_ASSERT(src_num_ivs <= shape_to_set_on_dest->capacity);
+ RUBY_ASSERT(src_num_ivs <= shape_to_set_on_dest->capacity || rb_shape_id(shape_to_set_on_dest) == OBJ_TOO_COMPLEX_SHAPE_ID);
if (initial_shape->capacity < shape_to_set_on_dest->capacity) {
rb_ensure_iv_list_size(dest, initial_shape->capacity, shape_to_set_on_dest->capacity);
dest_buf = ROBJECT_IVPTR(dest);