Run methods de fi ned in the space with the
de fi nition Namespace Ruby Process Namespace Application Code App::Func User Library Code DB::Client (v2) Library Code ActiveSupport (v7) Namespace Library Code DB::Client (v3) Namespace Application Code App::Func2 User Library Code ActiveSupport (v6) Application Code call call call
✦ struct RClass ✦ struct ✦ VALUE(Class object) ✦ struct
rb_classext_struct (rb_classext_t) ✦ struct ✦ many other class de fi nitions ✦ struct RClass_and_rb_classext_t ✦ RClass + classext Ruby’s Class de fi nition RClass + rb_classext_t RClass rb_classext_t RClass_and_rb_classext_t
(Ruby 3.4) Information in RClass + rb_classext_t struct RClass {
struct RBasic basic; VALUE super; struct rb_id_table *m_tbl; }; struct rb_classext_struct { VALUE *iv_ptr; struct rb_id_table *const_tbl; struct rb_id_table *callable_m_tbl; struct rb_id_table *cc_tbl; struct rb_id_table *cvc_tbl; size_t superclass_depth; VALUE *superclasses; struct rb_subclass_entry *subclasses; struct rb_subclass_entry *subclass_entry; struct rb_subclass_entry *module_subclass_entry; const VALUE origin_; const VALUE refined_class; union { class; singleton_class; } as; const VALUE includer; attr_index_t max_iv_count; unsigned char variation_count; bool permanent_classpath : 1; bool cloned : 1; VALUE classpath; };
(Namespace) Information in RClass + rb_classext_t struct RClass { struct
RBasic basic; st_table *ns_classext_tbl; bool prime_classext_readable : 1; bool prime_classext_writable : 1; }; struct rb_classext_struct { const rb_namespace_t *ns; VALUE super; VALUE *iv_ptr; struct rb_id_table *m_tbl; struct rb_id_table *const_tbl; struct rb_id_table *callable_m_tbl; struct rb_id_table *cc_tbl; struct rb_id_table *cvc_tbl; size_t superclass_depth; VALUE *superclasses; struct rb_subclass_anchor *subclasses; rb_ns_subclasses_t *ns_super_subclasses; rb_ns_subclasses_t *ns_module_subclasses; const VALUE origin_; const VALUE refined_class; union { class; singleton_class; } as; const VALUE includer; attr_index_t max_iv_count; unsigned char variation_count; bool permanent_classpath : 1; bool cloned : 1; bool shared_const_tbl : 1; bool iclass_is_origin : 1; bool iclass_origin_shared_mtbl : 1; bool superclasses_owner : 1; bool superclasses_with_self : 1; VALUE classpath; };
(Namespace) Information in RClass + rb_classext_t struct RClass { struct
RBasic basic; st_table *ns_classext_tbl; bool prime_classext_readable : 1; bool prime_classext_writable : 1; }; struct rb_classext_struct { const rb_namespace_t *ns; VALUE super; VALUE *iv_ptr; struct rb_id_table *m_tbl; struct rb_id_table *const_tbl; struct rb_id_table *callable_m_tbl; struct rb_id_table *cc_tbl; struct rb_id_table *cvc_tbl; size_t superclass_depth; VALUE *superclasses; struct rb_subclass_anchor *subclasses; rb_ns_subclasses_t *ns_super_subclasses; rb_ns_subclasses_t *ns_module_subclasses; const VALUE origin_; const VALUE refined_class; union { class; singleton_class; } as; const VALUE includer; attr_index_t max_iv_count; unsigned char variation_count; bool permanent_classpath : 1; bool cloned : 1; bool shared_const_tbl : 1; bool iclass_is_origin : 1; bool iclass_origin_shared_mtbl : 1; bool superclasses_owner : 1; bool superclasses_with_self : 1; VALUE classpath; }; NEW NEW Moved from RClass Changed data structure Moved from Object flag FL_USER*
✦ Di ff erent Namespace, di ff erent class de
fi nition ✦ classext per Namespace by shallow copying the values (at fi rst) Namespaces and classexts RClass ns_classext_tbl rb_classext_t for root/builtin namespace (prime) rb_classext_t for main namespace (non-prime) rb_classext_t for namespace X (non-prime) rb_classext for namespac Y (non-prime
✦ Di ff erent Namespace, di ff erent class de
fi nition ✦ classext per Namespace by shallow copying the values (at fi rst) Namespaces and classexts RClass ns_classext_tbl rb_classext_t for root/builtin namespace (prime) rb_classext_t for main namespace (non-prime) rb_classext_t for namespace X (non-prime) rb_classext for namespac Y (non-prime My Idea at that time 2
✦ Deleting the constant A causes xfree(va) ✦ And va
also exists in the const_tbl in the prime classext → SEGV! ✦ ASAN showed the root cause Deleting/Re-setting Constant on non-prime classext RClass ns_classext_tbl rb_classext_t (prime) const_tbl [A -> va] rb_classext_t (non-prime) const_tbl [] https://rubykaigi.org/2024/presentations/KJTsanaktsidis.html
✦ 💡🤩 Copy the .so fi le with its basename
and Namespace ✦ Di ff erent namespaces load di ff erent .so fi les Loading Extensions in Namespace (2) util.so Namespace A Namespace B dlopen(“a_util.so”) util_abc dlopen(“b_util.so”) util_abc My Idea at that time 5
✦ Copy the .so fi le with its basename and
Namespace ✦ “cgi/escape” in a → “a_escape.so” ✦ “erb/escape” in a → “a_escape.so” 🥶 ✦ What happens? when: 1. Overwriting the dlopen-ed .so fi le with others 2. Then calling dlopen() the .so fi le ✦ macOS: “Killed: 9” ✦ Linux: Nothing happened — then SEGV randomly Loading Extensions in Namespace (3)
✦ Copy the .so fi le with its full feature
name and Namespace ✦ feature name (fname): “cgi/escape”, “erb/escape” Loading Extensions in Namespace: Use Full Path cgi/escape Namespace A dlopen(“a_cgi+escape.so”) cgi_escape erb/escape erb_escape dlopen(“a_erb+escape.so”)
✦ Stacks (push/pop) for managing namespaces ✦ One day: Too
many pops on the stack — but why? ✦ rb_ensure() guards push/pop operations ✦ Bug #20655 ✦ Continuation (callcc, cont.call) triggers rb_ensure callback wrongly Bugs of MRI (1) cont.call triggers ensure in C VALUE rb_namespace_exec( const rb_namespace_t *ns, namespace_exec_func *func, VALUE arg) { rb_thread_t *th = GET_THREAD(); namespace_push(th, ns); return rb_ensure(func, arg, namespace_pop, (VALUE)th); } https://bugs.ruby-lang.org/issues/20655
✦ VM_ASSERT(cme->owner == T_CLASS) failed in clearing method caches ✦
cme: callable method entry ✦ method: require, de fi ned_class: Kernel, owner: Kernel ✦ Bug #20767, caused by “Implicit Re fi nements” for namespace implementation ✦ Reproduced by 1. re fi ne Kernel#require (then using it) 2. alias #require to #original_require 3. rede fi ning Kernel#require Bugs of MRI (2) Invalid cme owner with re fi nement
✦ ‘make check’ failed with SystemStackError ✦ Debug prints💡 —
prism called itself again and again ✦ Using “—parser=parse.y” solved this problem ✦ But why? ✦ I found a comment by ko1 in bootstraptest/test_ractor.rb ✦ “prism parser with -O0 build consumes a lot of machine stack” ✦ Compiler option “-O3” solved this problem… but why? Bugs? of MRI (3) Don’t use compiler option “-O0”
.png)

