From ca7ec5a0c3c49c181b600c977256fd88ab165b36 Mon Sep 17 00:00:00 2001 From: Shugo Maeda Date: Sat, 11 Jul 2026 08:30:22 +0900 Subject: [PATCH 1/6] Register clones with their superclass's subclass list Since a2531ba29303fab468c8084c07149040a7871219, class_associate_super() maintains subclass lists only for direct T_CLASS -> T_CLASS links. When a class that includes or prepends a module is cloned, rb_mod_init_copy() connects the clone (or its origin) to a T_ICLASS, so the clone was never added to its real superclass's subclass list and Class#subclasses did not return it. Register the clone with its superclass explicitly after the chain is built. rb_class_superclass() can be used because the superclass table is already up to date at this point and the superclass always exists (the root class cannot be cloned). Clones of classes without modules are registered by class_associate_super() as before. [Bug #22190] Co-Authored-By: Claude Fable 5 --- class.c | 7 +++++++ test/ruby/test_class.rb | 14 ++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/class.c b/class.c index 4e35285c610581..f591eb9a2e6deb 100644 --- a/class.c +++ b/class.c @@ -1047,6 +1047,13 @@ rb_mod_init_copy(VALUE clone, VALUE orig) rb_class_update_superclasses(clone); } + if (RB_TYPE_P(clone, T_CLASS)) { + VALUE super = RCLASS_SUPER(clone); + if (super && RB_TYPE_P(super, T_ICLASS)) { + class_switch_superclass(rb_class_superclass(clone), clone); + } + } + return clone; } diff --git a/test/ruby/test_class.rb b/test/ruby/test_class.rb index 82199876ecf35f..39968f2741675c 100644 --- a/test/ruby/test_class.rb +++ b/test/ruby/test_class.rb @@ -846,6 +846,20 @@ def test_subclasses end end + def test_subclasses_includes_clone + c = Class.new + with_include = Class.new(c) { include Module.new } + with_prepend = Class.new(c) { prepend Module.new } + plain = Class.new(c) + + bug22190 = '[ruby-core:126038] [Bug #22190]' + clones = [with_include, with_prepend, plain].flat_map {|k| [k.clone, k.dup]} + subclasses = c.subclasses + clones.each do |k| + assert_equal(1, subclasses.count(k), "#{bug22190} expected #{k.inspect} to appear in subclasses exactly once") + end + end + def test_attached_object c = Class.new sc = c.singleton_class From 674e93935c846f129329e78c4270015ed1805e80 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Thu, 16 Jul 2026 10:06:22 +0900 Subject: [PATCH 2/6] Use archname input for downloaded-cache path in tarball-windows.yml The cache step hardcoded snapshot-*, which no longer matches when this reusable workflow is called with a release archname such as ruby-3.4.0-rc1 from ruby/actions, turning cache save and restore into a no-op. Co-Authored-By: Claude Fable 5 --- .github/workflows/tarball-windows.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tarball-windows.yml b/.github/workflows/tarball-windows.yml index 24bfe8dde1bd00..7e32faa3b9395e 100644 --- a/.github/workflows/tarball-windows.yml +++ b/.github/workflows/tarball-windows.yml @@ -97,7 +97,7 @@ jobs: - uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: - path: snapshot-*/.downloaded-cache + path: ${{ inputs.archname }}/.downloaded-cache key: downloaded-cache - name: setup env From 3273d084bb2411783bb4b5626da77d3dcfc334a4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 16 Jul 2026 02:08:01 +0000 Subject: [PATCH 3/6] Bump zizmorcore/zizmor-action Bumps the github-actions group with 1 update in the / directory: [zizmorcore/zizmor-action](https://github.com/zizmorcore/zizmor-action). Updates `zizmorcore/zizmor-action` from 0.5.7 to 0.6.0 - [Release notes](https://github.com/zizmorcore/zizmor-action/releases) - [Commits](https://github.com/zizmorcore/zizmor-action/compare/192e21d79ab29983730a13d1382995c2307fbcaa...6599ee8b7a49aef6a770f63d261d214911a7ce02) --- updated-dependencies: - dependency-name: zizmorcore/zizmor-action dependency-version: 0.6.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions ... Signed-off-by: dependabot[bot] --- .github/workflows/check_sast.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check_sast.yml b/.github/workflows/check_sast.yml index dbe2f43bb475c8..3b4eb17646bb66 100644 --- a/.github/workflows/check_sast.yml +++ b/.github/workflows/check_sast.yml @@ -45,7 +45,7 @@ jobs: persist-credentials: false - name: Run zizmor - uses: zizmorcore/zizmor-action@192e21d79ab29983730a13d1382995c2307fbcaa # v0.5.7 + uses: zizmorcore/zizmor-action@6599ee8b7a49aef6a770f63d261d214911a7ce02 # v0.6.0 continue-on-error: true analyze: From 11bb5c82d2107f7609151e088eceecb8d9c71d97 Mon Sep 17 00:00:00 2001 From: Luke Gruber Date: Wed, 15 Jul 2026 18:39:29 -0400 Subject: [PATCH 4/6] Disable MacOS ReportCrash in Github Actions CI Hopefully this will mitigate MacOS timeouts for tests that are exercising the crash path (assert_segv, etc). --- .github/workflows/macos.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index ce81e15ed8a164..c8e32674832359 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -96,6 +96,17 @@ jobs: sudo sysctl -w kern.coredump=1 sudo chmod -R +rwx /cores/ + - name: Disable ReportCrash + # We don't want this service running on every crash signal. When it's running, processes must wait for + # the service to gather process info before they can finish. We have tests that test our crash signal + # handling and this service can take a while to run which can time our tests out. + run: | + launchctl bootout gui/"$(id -u)"/com.apple.ReportCrash 2>/dev/null || true + launchctl disable gui/"$(id -u)"/com.apple.ReportCrash 2>/dev/null || true + sudo launchctl bootout system/com.apple.ReportCrash.Root 2>/dev/null || true + sudo launchctl disable system/com.apple.ReportCrash.Root 2>/dev/null || true + continue-on-error: true + - name: Delete unused SDKs # To free up disk space to not run out during the run run: | From a78c2d52dca2054a6f5e58973325973461bf8914 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Thu, 16 Jul 2026 10:10:02 +0900 Subject: [PATCH 5/6] Remove SunOS 4 support SunOS 4 reached end of life in 2003 and the sunos* configure target has been unbuildable for decades. Solaris (SunOS 5, solaris*) is unaffected. --- configure.ac | 6 ------ 1 file changed, 6 deletions(-) diff --git a/configure.ac b/configure.ac index a461adc697cc80..9ae8acee9b6b95 100644 --- a/configure.ac +++ b/configure.ac @@ -3149,7 +3149,6 @@ STATIC= ], [ AS_CASE(["$target_os"], [solaris*|irix*], [CCDLFLAGS="$CCDLFLAGS -KPIC"], - [sunos*], [CCDLFLAGS="$CCDLFLAGS -PIC"], [esix*|uxpds*], [CCDLFLAGS="$CCDLFLAGS -KPIC"], [: ${CCDLFLAGS=""}]) ]) @@ -3190,8 +3189,6 @@ AC_SUBST(EXTOBJS) : ${PRELOADENV=LD_PRELOAD_32} ]) rb_cv_dlopen=yes], - [sunos*], [ : ${LDSHARED='$(LD) -assert nodefinitions'} - rb_cv_dlopen=yes], [irix*], [ : ${LDSHARED='$(LD) -shared'} rb_cv_dlopen=yes], [sysv4*], [ : ${LDSHARED='$(LD) -G'} @@ -3662,9 +3659,6 @@ AS_CASE("$enable_shared", [yes], [ relative_libprefix="/../${multiarch+../}${libdir_basename}" AS_CASE(["$target_os"], - [sunos4*], [ - LIBRUBY_ALIASES='$(LIBRUBY_SONAME) lib$(RUBY_SO_NAME).$(SOEXT)' - ], [linux* | gnu* | k*bsd*-gnu | atheos* | kopensolaris*-gnu | haiku*], [ RUBY_APPEND_OPTIONS(LIBRUBY_DLDFLAGS, ['-Wl,-soname,$(LIBRUBY_SONAME)' "$LDFLAGS_OPTDIR"]) LIBRUBY_ALIASES='$(LIBRUBY_SONAME) lib$(RUBY_SO_NAME).$(SOEXT)' From 99f2ef9c1fef5d5d13727db5b931453603d2e15a Mon Sep 17 00:00:00 2001 From: Shugo Maeda Date: Thu, 16 Jul 2026 14:27:51 +0900 Subject: [PATCH 6/6] Fix data race in rb_iseq_original_iseq The translated code cache was published before its contents were initialized, so a concurrent caller could read direct-threaded addresses as instruction numbers. Reachable since Proc#refined started dumping the same iseq from multiple Ractors. Build the buffer locally and publish it with CAS after translation. --- compile.c | 15 ++++++++++++--- iseq.h | 7 ------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/compile.c b/compile.c index 3888134c7c8402..41aee58f75570d 100644 --- a/compile.c +++ b/compile.c @@ -1003,10 +1003,10 @@ rb_iseq_translate_threaded_code(rb_iseq_t *iseq) VALUE * rb_iseq_original_iseq(const rb_iseq_t *iseq) /* cold path */ { - VALUE *original_code; + VALUE *original_code = RUBY_ATOMIC_PTR_LOAD(ISEQ_BODY(iseq)->variable.original_iseq); - if (ISEQ_ORIGINAL_ISEQ(iseq)) return ISEQ_ORIGINAL_ISEQ(iseq); - original_code = ISEQ_ORIGINAL_ISEQ_ALLOC(iseq, ISEQ_BODY(iseq)->iseq_size); + if (original_code) return original_code; + original_code = ALLOC_N(VALUE, ISEQ_BODY(iseq)->iseq_size); MEMCPY(original_code, ISEQ_BODY(iseq)->iseq_encoded, VALUE, ISEQ_BODY(iseq)->iseq_size); #if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE @@ -1022,6 +1022,15 @@ rb_iseq_original_iseq(const rb_iseq_t *iseq) /* cold path */ } } #endif + + /* Concurrent callers can each build a copy; publish only fully + * translated code and keep the first one. */ + VALUE *prev = ATOMIC_PTR_CAS(ISEQ_BODY(iseq)->variable.original_iseq, + NULL, original_code); + if (prev) { + SIZED_FREE_N(original_code, ISEQ_BODY(iseq)->iseq_size); + return prev; + } return original_code; } diff --git a/iseq.h b/iseq.h index df74ec86e3fdf4..b346ad0da013e6 100644 --- a/iseq.h +++ b/iseq.h @@ -75,13 +75,6 @@ ISEQ_ORIGINAL_ISEQ_CLEAR(const rb_iseq_t *iseq) } } -static inline VALUE * -ISEQ_ORIGINAL_ISEQ_ALLOC(const rb_iseq_t *iseq, long size) -{ - return ISEQ_BODY(iseq)->variable.original_iseq = - ALLOC_N(VALUE, size); -} - #define ISEQ_TRACE_EVENTS (RUBY_EVENT_LINE | \ RUBY_EVENT_CLASS | \ RUBY_EVENT_END | \