Skip to content

Commit d5af8d7

Browse files
committed
Box: allocate classes as boxable when it happens in the root box
Without this change, classes (including iclass) are allocated as un-boxable classes after initializing user boxes (after starting script evaluation). Under this situation, iclasses are created as un-boxabled class when core modules are included by a class in the root box, then it causes problems because it's in the root box but it can't have multiple classexts. This change makes it possible to allocate boxable classes even after initializing user boxes. Classes create in the root box will be boxable, and those can have 2 or more classexts.
1 parent 65634d8 commit d5af8d7

File tree

2 files changed

+19
-1
lines changed

2 files changed

+19
-1
lines changed

class.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,7 @@ rb_class_duplicate_classext(rb_classext_t *orig, VALUE klass, const rb_box_t *bo
491491
while (subclass_entry) {
492492
if (subclass_entry->klass && RB_TYPE_P(subclass_entry->klass, T_ICLASS)) {
493493
iclass = subclass_entry->klass;
494+
VM_ASSERT(RB_TYPE_P(iclass, T_ICLASS));
494495
if (RBASIC_CLASS(iclass) == klass) {
495496
// Is the subclass an ICLASS including this module into another class
496497
// If so we need to re-associate it under our box with the new ext
@@ -819,7 +820,8 @@ class_alloc0(enum ruby_value_type type, VALUE klass, bool boxable)
819820
static VALUE
820821
class_alloc(enum ruby_value_type type, VALUE klass)
821822
{
822-
return class_alloc0(type, klass, false);
823+
bool boxable = BOX_ROOT_P(rb_current_box());
824+
return class_alloc0(type, klass, boxable);
823825
}
824826

825827
static VALUE

test/ruby/test_box.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -855,4 +855,20 @@ def test_loaded_extension_deleted_in_user_box
855855
assert_empty(Dir.children(tmpdir))
856856
end
857857
end
858+
859+
def test_root_box_iclasses_should_be_boxable
860+
assert_separately([ENV_ENABLE_BOX], __FILE__, __LINE__, "#{<<~"begin;"}\n#{<<~'end;'}", ignore_stderr: true)
861+
begin;
862+
Ruby::Box.root.eval("class IMath; include Math; end") # (*)
863+
module Math
864+
def foo = :foo
865+
end
866+
# This test crashes here if iclasses (created at the line (*) is not boxable)
867+
class IMath2; include Math; end
868+
assert_equal :foo, IMath2.new.foo
869+
assert_raise NoMethodError do
870+
Ruby::Box.root.eval("IMath.new.foo")
871+
end
872+
end;
873+
end
858874
end

0 commit comments

Comments
 (0)