<feed xmlns='http://www.w3.org/2005/Atom'>
<title>ruby.git/internal/class.h, branch v4.0.4</title>
<subtitle>The Ruby Programming Language</subtitle>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/'/>
<entry>
<title>merge revision(s) c0d86a0103de7130943d54b4a290b76ec7e0c135,47e061277ac194a36659510bcf4f3190bde629a6: [Backport #21952]</title>
<updated>2026-05-11T20:54:55+00:00</updated>
<author>
<name>Takashi Kokubun</name>
<email>takashikkbn@gmail.com</email>
</author>
<published>2026-05-11T20:54:55+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=8539f0b386e2e42f8fe5ac12a2fd9e84872d8c7c'/>
<id>8539f0b386e2e42f8fe5ac12a2fd9e84872d8c7c</id>
<content type='text'>
	class.c: rb_class_duplicate_classext also dup content of cvc_tbl

	[Bug #21952]

	Shallow copying the table result in the same memory being shared
	between multiple box, causing double free when one of the box
	is garbage collected.

	---

	class.c: Make cvc_tbl a managed object

	[Bug #21952]

	Solves the double-free or use after-free concern with boxes.
	Now entries can safely be used for copy-on-write.

	Also is likely necessary to make it save to read cvar from
	secondary ractors, as allowed since: ab32c0e690b805cdaaf264ad4c3421696c588204
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
	class.c: rb_class_duplicate_classext also dup content of cvc_tbl

	[Bug #21952]

	Shallow copying the table result in the same memory being shared
	between multiple box, causing double free when one of the box
	is garbage collected.

	---

	class.c: Make cvc_tbl a managed object

	[Bug #21952]

	Solves the double-free or use after-free concern with boxes.
	Now entries can safely be used for copy-on-write.

	Also is likely necessary to make it save to read cvar from
	secondary ractors, as allowed since: ab32c0e690b805cdaaf264ad4c3421696c588204
</pre>
</div>
</content>
</entry>
<entry>
<title>Simplify subclasses list, remove from Box</title>
<updated>2026-03-20T00:57:58+00:00</updated>
<author>
<name>John Hawthorn</name>
<email>john@hawthorn.email</email>
</author>
<published>2026-03-10T19:10:41+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=2b22593ac12d0e8cbcf8299f0fea14c6311715d8'/>
<id>2b22593ac12d0e8cbcf8299f0fea14c6311715d8</id>
<content type='text'>
Currently we maintain the subclasses list for two separate purposes (we essentially have to different relationships we're putting into the same list):

1. On a T_MODULE, we track the T_ICLASSes created to include it into
   other classes. Used for method invalidation and propagating includes
   on the module that happen after it's been used
2. On a T_CLASS/T_ICLASS, we track the T_CLASS/T_ICLASS which are the
   immediate children of the class. We use this for method invalidation,
   some cvar things, and to iterate through subclasses.

Purpose 1 does not have any issues with box, the T_ICLASS always belongs
to one specific module and that's immutable. This list can be box-global
(always use the prime classext or hoist it out) and only needs to be
pruned during free. If we care about behaviour under a particular box
(ie. the propagating includes), we should look up the current box being
modified on the ICLASS itself.

Purpose 2 is more complicated. It currently tracks the immediate
children, the T_CLASS or T_ICLASS whose super points back. Because super
is per-box and is mutable (include/prepend insert ICLASSes into the
chain) we need to update the list on include/prepend, entries must be
per-box, and we can have multiple entries per-box. *I propose we
simplify this by no longer tracking the immediate subclass*, but instead
tracking the T_CLASS -&gt; ... -&gt; T_CLASS relationship, ie. the inverse of
rb_class_superclass. That relationship is the same across all boxes and
immutable after Class creation.

As a special case the ICLASS for refinements are also added to the
purpose 2 list (on T_CLASS). As those ICLASS do not chain to an eventual
leaf T_CLASS.

When we need to find the classes which have included a module, we can
use the module subclasses list to find the ICLASS and then use
RCLASS_INCLUDER. If we needed to iterate all T_ICLASS, we could then
walk up the CLASS_SUPER chain, but I didn't find anywhere we needed to
do that.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Currently we maintain the subclasses list for two separate purposes (we essentially have to different relationships we're putting into the same list):

1. On a T_MODULE, we track the T_ICLASSes created to include it into
   other classes. Used for method invalidation and propagating includes
   on the module that happen after it's been used
2. On a T_CLASS/T_ICLASS, we track the T_CLASS/T_ICLASS which are the
   immediate children of the class. We use this for method invalidation,
   some cvar things, and to iterate through subclasses.

Purpose 1 does not have any issues with box, the T_ICLASS always belongs
to one specific module and that's immutable. This list can be box-global
(always use the prime classext or hoist it out) and only needs to be
pruned during free. If we care about behaviour under a particular box
(ie. the propagating includes), we should look up the current box being
modified on the ICLASS itself.

Purpose 2 is more complicated. It currently tracks the immediate
children, the T_CLASS or T_ICLASS whose super points back. Because super
is per-box and is mutable (include/prepend insert ICLASSes into the
chain) we need to update the list on include/prepend, entries must be
per-box, and we can have multiple entries per-box. *I propose we
simplify this by no longer tracking the immediate subclass*, but instead
tracking the T_CLASS -&gt; ... -&gt; T_CLASS relationship, ie. the inverse of
rb_class_superclass. That relationship is the same across all boxes and
immutable after Class creation.

As a special case the ICLASS for refinements are also added to the
purpose 2 list (on T_CLASS). As those ICLASS do not chain to an eventual
leaf T_CLASS.

When we need to find the classes which have included a module, we can
use the module subclasses list to find the ICLASS and then use
RCLASS_INCLUDER. If we needed to iterate all T_ICLASS, we could then
walk up the CLASS_SUPER chain, but I didn't find anywhere we needed to
do that.
</pre>
</div>
</content>
</entry>
<entry>
<title>Speed up class allocator search</title>
<updated>2025-12-11T17:53:10+00:00</updated>
<author>
<name>John Hawthorn</name>
<email>john@hawthorn.email</email>
</author>
<published>2025-12-06T07:31:33+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=32e6dc0f31b98cf17dd9ace46561d74a55966b20'/>
<id>32e6dc0f31b98cf17dd9ace46561d74a55966b20</id>
<content type='text'>
This rewrites the class allocator search to be faster. Instead of using
RCLASS_SUPER, which is now even slower due to Box, we can scan the
superclasses list to find a class where the allocator is defined.

This also disallows allocating from an ICLASS. Previously I believe that
was only done for FrozenCore, and that was changed in
e596cf6e93dbf121e197cccfec8a69902e00eda3.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
This rewrites the class allocator search to be faster. Instead of using
RCLASS_SUPER, which is now even slower due to Box, we can scan the
superclasses list to find a class where the allocator is defined.

This also disallows allocating from an ICLASS. Previously I believe that
was only done for FrozenCore, and that was changed in
e596cf6e93dbf121e197cccfec8a69902e00eda3.
</pre>
</div>
</content>
</entry>
<entry>
<title>Box: Free rb_classext_t struct for a box when the box is GCed</title>
<updated>2025-12-02T14:49:49+00:00</updated>
<author>
<name>Satoshi Tagomori</name>
<email>s-tagomori@sakura.ad.jp</email>
</author>
<published>2025-11-30T08:50:50+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=9eafeaed67903bbf2f2dca5eb473c1bf774712f6'/>
<id>9eafeaed67903bbf2f2dca5eb473c1bf774712f6</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
<entry>
<title>Revert "ns_subclasses refcount accesses need to be atomic (#15083)" (#15138)</title>
<updated>2025-11-11T02:52:43+00:00</updated>
<author>
<name>Luke Gruber</name>
<email>luke.gruber@shopify.com</email>
</author>
<published>2025-11-11T02:52:43+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=148fde27545ee35c8aab4ec7bca027184d79fbc4'/>
<id>148fde27545ee35c8aab4ec7bca027184d79fbc4</id>
<content type='text'>
This reverts commit 2998c8d6b99ec49925ebea42198b29c3e27b34a7.

We need to find a better way to fix this bug. Even with this refcount
change, errors were still being seen in CI. For now we need to remove
this failing test.</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
This reverts commit 2998c8d6b99ec49925ebea42198b29c3e27b34a7.

We need to find a better way to fix this bug. Even with this refcount
change, errors were still being seen in CI. For now we need to remove
this failing test.</pre>
</div>
</content>
</entry>
<entry>
<title>Remove unused subclass methods</title>
<updated>2025-11-10T23:55:38+00:00</updated>
<author>
<name>John Hawthorn</name>
<email>john@hawthorn.email</email>
</author>
<published>2025-11-08T00:15:38+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=6238b6f53e4b10a1833eb90320f002f60be72d42'/>
<id>6238b6f53e4b10a1833eb90320f002f60be72d42</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
<entry>
<title>renaming internal data structures and functions from namespace to box</title>
<updated>2025-11-07T04:14:54+00:00</updated>
<author>
<name>Satoshi Tagomori</name>
<email>s-tagomori@sakura.ad.jp</email>
</author>
<published>2025-11-05T07:09:45+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=d2a587c79156275f66035d60bcc69882be61a3e1'/>
<id>d2a587c79156275f66035d60bcc69882be61a3e1</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
<entry>
<title>update referenced filenames from namespace to box</title>
<updated>2025-11-07T04:14:54+00:00</updated>
<author>
<name>Satoshi Tagomori</name>
<email>s-tagomori@sakura.ad.jp</email>
</author>
<published>2025-11-05T05:29:25+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=aaa1234702f0186b1cd7d2cea136eee20fc82153'/>
<id>aaa1234702f0186b1cd7d2cea136eee20fc82153</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
<entry>
<title>ns_subclasses refcount accesses need to be atomic (#15083)</title>
<updated>2025-11-06T21:32:20+00:00</updated>
<author>
<name>Luke Gruber</name>
<email>luke.gruber@shopify.com</email>
</author>
<published>2025-11-06T21:32:20+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=2998c8d6b99ec49925ebea42198b29c3e27b34a7'/>
<id>2998c8d6b99ec49925ebea42198b29c3e27b34a7</id>
<content type='text'>
We were seeing errors like:

```
* thread #8, stop reason = EXC_BAD_ACCESS (code=1, address=0x803)
  * frame #0: 0x00000001001fe944 ruby`rb_st_lookup(tab=0x00000000000007fb, key=1, value=0x00000001305b7490) at st.c:1066:22
    frame #1: 0x000000010002d658 ruby`remove_class_from_subclasses [inlined] class_get_subclasses_for_ns(tbl=0x00000000000007fb, ns_id=1) at class.c:604:9
    frame #2: 0x000000010002d650 ruby`remove_class_from_subclasses(tbl=0x00000000000007fb, ns_id=1, klass=4754039232) at class.c:620:34
    frame #3: 0x000000010002c8a8 ruby`rb_class_classext_free_subclasses(ext=0x000000011b5ce1d8, klass=4754039232, replacing=&lt;unavailable&gt;) at class.c:700:9
    frame #4: 0x000000010002c760 ruby`rb_class_classext_free(klass=4754039232, ext=0x000000011b5ce1d8, is_prime=true) at class.c:105:5
    frame #5: 0x00000001000e770c ruby`classext_free(ext=&lt;unavailable&gt;, is_prime=&lt;unavailable&gt;, namespace=&lt;unavailable&gt;, arg=&lt;unavailable&gt;) at gc.c:1231:5 [artificial]
    frame #6: 0x000000010002d178 ruby`rb_class_classext_foreach(klass=&lt;unavailable&gt;, func=(ruby`classext_free at gc.c:1228), arg=0x00000001305b75c0) at class.c:518:5
    frame #7: 0x00000001000e745c ruby`rb_gc_obj_free(objspace=0x000000012500c400, obj=4754039232) at gc.c:1282:9
    frame #8: 0x00000001000e70d4 ruby`gc_sweep_plane(objspace=0x000000012500c400, heap=&lt;unavailable&gt;, p=4754039232, bitset=4095, ctx=0x00000001305b76e8) at default.c:3482:21
    frame #9: 0x00000001000e6e9c ruby`gc_sweep_page(objspace=0x000000012500c400, heap=0x000000012500c540, ctx=0x00000001305b76e8) at default.c:3567:13
    frame #10: 0x00000001000e51d0 ruby`gc_sweep_step(objspace=0x000000012500c400, heap=0x000000012500c540) at default.c:3848:9
    frame #11: 0x00000001000e1880 ruby`gc_continue [inlined] gc_sweep_continue(objspace=0x000000012500c400, sweep_heap=0x000000012500c540) at default.c:3931:13
    frame #12: 0x00000001000e1754 ruby`gc_continue(objspace=0x000000012500c400, heap=0x000000012500c540) at default.c:2037:9
    frame #13: 0x00000001000e10bc ruby`newobj_cache_miss [inlined] heap_prepare(objspace=0x000000012500c400, heap=0x000000012500c540) at default.c:2056:5
    frame #14: 0x00000001000e1074 ruby`newobj_cache_miss [inlined] heap_next_free_page(objspace=0x000000012500c400, heap=0x000000012500c540) at default.c:2280:9
    frame #15: 0x00000001000e106c ruby`newobj_cache_miss(objspace=0x000000012500c400, cache=0x0000600001b00300, heap_idx=2, vm_locked=false) at default.c:2387:38
    frame #16: 0x00000001000e0d28 ruby`newobj_alloc(objspace=&lt;unavailable&gt;, cache=&lt;unavailable&gt;, heap_idx=&lt;unavailable&gt;, vm_locked=&lt;unavailable&gt;) at default.c:2411:15 [artificial]
    frame #17: 0x00000001000d7214 ruby`newobj_of [inlined] rb_gc_impl_new_obj(objspace_ptr=&lt;unavailable&gt;, cache_ptr=&lt;unavailable&gt;, klass=&lt;unavailable&gt;, flags=&lt;unavailable&gt;, wb_protected=&lt;unavailable&gt;, alloc_size=&lt;unavailable&gt;) at default.c:2490:15
    frame #18: 0x00000001000d719c ruby`newobj_of(cr=&lt;unavailable&gt;, klass=4313971728, flags=258, wb_protected=&lt;unavailable&gt;, size=&lt;unavailable&gt;) at gc.c:995:17
    frame #19: 0x00000001000d73ec ruby`rb_wb_protected_newobj_of(ec=&lt;unavailable&gt;, klass=&lt;unavailable&gt;, flags=&lt;unavailable&gt;, size=&lt;unavailable&gt;) at gc.c:1044:12 [artificial]
    frame #20: 0x0000000100032d34 ruby`class_alloc0(type=&lt;unavailable&gt;, klass=4313971728, namespaceable=&lt;unavailable&gt;) at class.c:803:5
```</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
We were seeing errors like:

```
* thread #8, stop reason = EXC_BAD_ACCESS (code=1, address=0x803)
  * frame #0: 0x00000001001fe944 ruby`rb_st_lookup(tab=0x00000000000007fb, key=1, value=0x00000001305b7490) at st.c:1066:22
    frame #1: 0x000000010002d658 ruby`remove_class_from_subclasses [inlined] class_get_subclasses_for_ns(tbl=0x00000000000007fb, ns_id=1) at class.c:604:9
    frame #2: 0x000000010002d650 ruby`remove_class_from_subclasses(tbl=0x00000000000007fb, ns_id=1, klass=4754039232) at class.c:620:34
    frame #3: 0x000000010002c8a8 ruby`rb_class_classext_free_subclasses(ext=0x000000011b5ce1d8, klass=4754039232, replacing=&lt;unavailable&gt;) at class.c:700:9
    frame #4: 0x000000010002c760 ruby`rb_class_classext_free(klass=4754039232, ext=0x000000011b5ce1d8, is_prime=true) at class.c:105:5
    frame #5: 0x00000001000e770c ruby`classext_free(ext=&lt;unavailable&gt;, is_prime=&lt;unavailable&gt;, namespace=&lt;unavailable&gt;, arg=&lt;unavailable&gt;) at gc.c:1231:5 [artificial]
    frame #6: 0x000000010002d178 ruby`rb_class_classext_foreach(klass=&lt;unavailable&gt;, func=(ruby`classext_free at gc.c:1228), arg=0x00000001305b75c0) at class.c:518:5
    frame #7: 0x00000001000e745c ruby`rb_gc_obj_free(objspace=0x000000012500c400, obj=4754039232) at gc.c:1282:9
    frame #8: 0x00000001000e70d4 ruby`gc_sweep_plane(objspace=0x000000012500c400, heap=&lt;unavailable&gt;, p=4754039232, bitset=4095, ctx=0x00000001305b76e8) at default.c:3482:21
    frame #9: 0x00000001000e6e9c ruby`gc_sweep_page(objspace=0x000000012500c400, heap=0x000000012500c540, ctx=0x00000001305b76e8) at default.c:3567:13
    frame #10: 0x00000001000e51d0 ruby`gc_sweep_step(objspace=0x000000012500c400, heap=0x000000012500c540) at default.c:3848:9
    frame #11: 0x00000001000e1880 ruby`gc_continue [inlined] gc_sweep_continue(objspace=0x000000012500c400, sweep_heap=0x000000012500c540) at default.c:3931:13
    frame #12: 0x00000001000e1754 ruby`gc_continue(objspace=0x000000012500c400, heap=0x000000012500c540) at default.c:2037:9
    frame #13: 0x00000001000e10bc ruby`newobj_cache_miss [inlined] heap_prepare(objspace=0x000000012500c400, heap=0x000000012500c540) at default.c:2056:5
    frame #14: 0x00000001000e1074 ruby`newobj_cache_miss [inlined] heap_next_free_page(objspace=0x000000012500c400, heap=0x000000012500c540) at default.c:2280:9
    frame #15: 0x00000001000e106c ruby`newobj_cache_miss(objspace=0x000000012500c400, cache=0x0000600001b00300, heap_idx=2, vm_locked=false) at default.c:2387:38
    frame #16: 0x00000001000e0d28 ruby`newobj_alloc(objspace=&lt;unavailable&gt;, cache=&lt;unavailable&gt;, heap_idx=&lt;unavailable&gt;, vm_locked=&lt;unavailable&gt;) at default.c:2411:15 [artificial]
    frame #17: 0x00000001000d7214 ruby`newobj_of [inlined] rb_gc_impl_new_obj(objspace_ptr=&lt;unavailable&gt;, cache_ptr=&lt;unavailable&gt;, klass=&lt;unavailable&gt;, flags=&lt;unavailable&gt;, wb_protected=&lt;unavailable&gt;, alloc_size=&lt;unavailable&gt;) at default.c:2490:15
    frame #18: 0x00000001000d719c ruby`newobj_of(cr=&lt;unavailable&gt;, klass=4313971728, flags=258, wb_protected=&lt;unavailable&gt;, size=&lt;unavailable&gt;) at gc.c:995:17
    frame #19: 0x00000001000d73ec ruby`rb_wb_protected_newobj_of(ec=&lt;unavailable&gt;, klass=&lt;unavailable&gt;, flags=&lt;unavailable&gt;, size=&lt;unavailable&gt;) at gc.c:1044:12 [artificial]
    frame #20: 0x0000000100032d34 ruby`class_alloc0(type=&lt;unavailable&gt;, klass=4313971728, namespaceable=&lt;unavailable&gt;) at class.c:803:5
```</pre>
</div>
</content>
</entry>
<entry>
<title>Stop deleting the reference from superclass when replacing classext.</title>
<updated>2025-10-26T08:49:39+00:00</updated>
<author>
<name>Satoshi Tagomori</name>
<email>s-tagomori@sakura.ad.jp</email>
</author>
<published>2025-10-25T04:36:20+00:00</published>
<link rel='alternate' type='text/html' href='https://git.ruby-lang.org/ruby.git/commit/?id=f53b8194cd5958619dc295e51dbdec29351a6b0a'/>
<id>f53b8194cd5958619dc295e51dbdec29351a6b0a</id>
<content type='text'>
Calling the usual rb_iclass_classext_free() causes SEGV because
duplicating a newer classext of iclass had set the reference from superclass
to the newer classext, but calling rb_iclass_classext_free() deletes it.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Calling the usual rb_iclass_classext_free() causes SEGV because
duplicating a newer classext of iclass had set the reference from superclass
to the newer classext, but calling rb_iclass_classext_free() deletes it.
</pre>
</div>
</content>
</entry>
</feed>
