From e569048b8a829d5ae65fab4f8243e0ecd5c62338 Mon Sep 17 00:00:00 2001 From: Peter Zhu Date: Fri, 14 Aug 2026 19:49:50 +0900 Subject: [PATCH 1/7] [DOC] Fix language/exceptions.md --- doc/language/exceptions.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/language/exceptions.md b/doc/language/exceptions.md index 5f8f0ece69d2e6..9e2f40646d6e7f 100644 --- a/doc/language/exceptions.md +++ b/doc/language/exceptions.md @@ -19,7 +19,7 @@ A raised exception transfers program execution, one way or another. ### Unrescued Exceptions -If an exception not _rescued_ +If an exception is not _rescued_ (see [Rescued Exceptions](#label-Rescued+Exceptions) below), execution transfers to code in the Ruby interpreter that prints a message and exits the program (or thread): @@ -63,7 +63,7 @@ An exception handler has several elements: | One or more rescue clauses. | Each contains "rescuing" code, which is to be executed for certain exceptions. | | Else clause (optional). | Contains code to be executed if no exception is raised. | | Ensure clause (optional). | Contains code to be executed whether or not an exception is raised, or is rescued. | -| end statement. | Ends the handler. ` | +| end statement. | Ends the handler. | #### Begin Clause @@ -159,7 +159,7 @@ Rescued Errno::ENOENT A `rescue` statement may specify a variable whose value becomes the rescued exception -(an instance of Exception or one of its subclasses: +(an instance of Exception or one of its subclasses): ```rb begin From b89f251284679d7e29562fa83666dd7cacaa1846 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Sun, 16 Aug 2026 22:05:32 +0900 Subject: [PATCH 2/7] Update clang for LTO --- .github/workflows/compilers.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/compilers.yml b/.github/workflows/compilers.yml index e5c964ad39d4e5..2ec9137fa018f0 100644 --- a/.github/workflows/compilers.yml +++ b/.github/workflows/compilers.yml @@ -60,11 +60,11 @@ jobs: with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false } # Set fetch-depth: 10 so that Launchable can receive commits information. - { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true, fetch-depth: 10 } } - - name: 'clang 22 LTO' + - name: 'clang 23 LTO' uses: './.github/actions/compilers' with: - tag: clang-22 - with_gcc: 'clang-22 -flto=auto' + tag: clang-23 + with_gcc: 'clang-23 -flto=auto' optflags: '-O2' timeout-minutes: 30 - { uses: './.github/actions/compilers', name: '-O0', with: { optflags: '-O0 -march=x86-64 -mtune=generic' }, timeout-minutes: 8 } From 742dd93270b478463a08ba9d312ccb8811d8351a Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Mon, 17 Aug 2026 22:34:18 +0900 Subject: [PATCH 3/7] Prepare Compilations sources once Share a generated source archive across compiler jobs to avoid repeating checkout and `make up` on every runner. --- .../setup/compilation-source/action.yml | 28 +++++++++ .github/workflows/compilers.yml | 63 ++++++++++++++----- 2 files changed, 75 insertions(+), 16 deletions(-) create mode 100644 .github/actions/setup/compilation-source/action.yml diff --git a/.github/actions/setup/compilation-source/action.yml b/.github/actions/setup/compilation-source/action.yml new file mode 100644 index 00000000000000..27f2098240c26d --- /dev/null +++ b/.github/actions/setup/compilation-source/action.yml @@ -0,0 +1,28 @@ +name: Set up sources for Compilations +description: Download and extract sources prepared by the Compilations workflow. + +runs: + using: composite + steps: + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: compilation-source + path: ${{ runner.temp }} + + - shell: bash + working-directory: ${{ github.workspace }} + run: tar -xf "${RUNNER_TEMP}/compilation-source.tar" + + - id: gems-key + shell: bash + run: echo "hash=${HASH}" >> "${GITHUB_OUTPUT}" + env: + HASH: ${{ hashFiles('src/gems/bundled_gems') }} + + - uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 + with: + path: src/.downloaded-cache + key: downloaded-cache-${{ steps.gems-key.outputs.hash }} + restore-keys: | + downloaded-cache- + ${{ runner.os }}-${{ runner.arch }}-downloaded-cache diff --git a/.github/workflows/compilers.yml b/.github/workflows/compilers.yml index 2ec9137fa018f0..6f77d2e95a94db 100644 --- a/.github/workflows/compilers.yml +++ b/.github/workflows/compilers.yml @@ -35,7 +35,7 @@ env: # Each job is split so that they roughly take 30min to run through. jobs: compile-if: - name: 'omnibus compilations, trigger' + name: 'omnibus compilations, source' runs-on: ubuntu-latest if: >- ${{!(false @@ -44,9 +44,26 @@ jobs: || contains(github.event.pull_request.labels.*.name, 'Documentation') || (github.event.pull_request.user.login == 'dependabot[bot]') )}} + timeout-minutes: 10 + steps: - - run: true - working-directory: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false } + # Set fetch-depth: 10 so that Launchable can receive commits information. + - { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true, fetch-depth: 10 } } + - name: Archive sources + working-directory: ${{ github.workspace }} + # `.downloaded-cache` will be restored from the common cache + run: >- + tar -cf "${RUNNER_TEMP}/compilation-source.tar" + --exclude='src/.downloaded-cache' + src + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: compilation-source + path: ${{ runner.temp }}/compilation-source.tar + compression-level: 0 + retention-days: 1 compile1: name: 'omnibus compilations, #1' @@ -58,8 +75,7 @@ jobs: steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false } - # Set fetch-depth: 10 so that Launchable can receive commits information. - - { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true, fetch-depth: 10 } } + - uses: './.github/actions/setup/compilation-source' - name: 'clang 23 LTO' uses: './.github/actions/compilers' with: @@ -80,7 +96,7 @@ jobs: steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false } - - { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true, fetch-depth: 10 } } + - uses: './.github/actions/setup/compilation-source' - name: 'GCC 15 LTO' uses: './.github/actions/compilers' with: @@ -108,7 +124,7 @@ jobs: steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false } - - { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true, fetch-depth: 10 } } + - uses: './.github/actions/setup/compilation-source' - { uses: './.github/actions/compilers', name: 'clang 20', with: { tag: 'clang-20' }, timeout-minutes: 8 } - { uses: './.github/actions/compilers', name: 'clang 19', with: { tag: 'clang-19' }, timeout-minutes: 8 } - { uses: './.github/actions/compilers', name: 'clang 18', with: { tag: 'clang-18' }, timeout-minutes: 8 } @@ -127,7 +143,7 @@ jobs: steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false } - - { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true, fetch-depth: 10 } } + - uses: './.github/actions/setup/compilation-source' - { uses: './.github/actions/compilers', name: 'clang 13', with: { tag: 'clang-13' }, timeout-minutes: 8 } - { uses: './.github/actions/compilers', name: 'clang 12', with: { tag: 'clang-12' }, timeout-minutes: 8 } - { uses: './.github/actions/compilers', name: 'clang 11', with: { tag: 'clang-11' }, timeout-minutes: 8 } @@ -148,7 +164,7 @@ jobs: steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false } - - { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true, fetch-depth: 10 } } + - uses: './.github/actions/setup/compilation-source' # -Wno-strict-prototypes is necessary with clang-15 or newer, since # older autoconf prior to 2.72 generate functions without prototype # and -pedantic now implies strict-prototypes. Disabling the error @@ -174,7 +190,7 @@ jobs: steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false } - - { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true, fetch-depth: 10 } } + - uses: './.github/actions/setup/compilation-source' - { uses: './.github/actions/compilers', name: 'C++20', with: { CXXFLAGS: '-std=c++20 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' }, timeout-minutes: 8 } - { uses: './.github/actions/compilers', name: 'C++23', with: { CXXFLAGS: '-std=c++23 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' }, timeout-minutes: 8 } - { uses: './.github/actions/compilers', name: 'C++26', with: { CXXFLAGS: '-std=c++26 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' }, timeout-minutes: 8 } @@ -194,7 +210,7 @@ jobs: steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false } - - { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true, fetch-depth: 10 } } + - uses: './.github/actions/setup/compilation-source' - { uses: './.github/actions/compilers', name: 'disable-jit', with: { append_configure: '--disable-yjit --disable-zjit' }, timeout-minutes: 8 } - { uses: './.github/actions/compilers', name: 'disable-yjit', with: { append_configure: '--disable-yjit' }, timeout-minutes: 8 } - { uses: './.github/actions/compilers', name: 'disable-zjit', with: { append_configure: '--disable-zjit' }, timeout-minutes: 8 } @@ -214,7 +230,7 @@ jobs: steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false } - - { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true, fetch-depth: 10 } } + - uses: './.github/actions/setup/compilation-source' - { uses: './.github/actions/compilers', name: 'NDEBUG', with: { cppflags: '-DNDEBUG' }, timeout-minutes: 8 } - { uses: './.github/actions/compilers', name: 'RUBY_DEBUG', with: { cppflags: '-DRUBY_DEBUG' }, timeout-minutes: 8 } - { uses: './.github/actions/compilers', name: 'ARRAY_DEBUG', with: { cppflags: '-DARRAY_DEBUG' }, timeout-minutes: 8 } @@ -233,7 +249,7 @@ jobs: steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false } - - { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true, fetch-depth: 10 } } + - uses: './.github/actions/setup/compilation-source' - { uses: './.github/actions/compilers', name: 'HASH_DEBUG', with: { cppflags: '-DHASH_DEBUG' }, timeout-minutes: 8 } - { uses: './.github/actions/compilers', name: 'ID_TABLE_DEBUG', with: { cppflags: '-DID_TABLE_DEBUG' }, timeout-minutes: 8 } - { uses: './.github/actions/compilers', name: 'RGENGC_DEBUG=-1', with: { cppflags: '-DRGENGC_DEBUG=-1' }, timeout-minutes: 8 } @@ -253,7 +269,7 @@ jobs: steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false } - - { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true, fetch-depth: 10 } } + - uses: './.github/actions/setup/compilation-source' - { uses: './.github/actions/compilers', name: 'USE_LAZY_LOAD', with: { cppflags: '-DUSE_LAZY_LOAD' }, timeout-minutes: 8 } - { uses: './.github/actions/compilers', name: 'USE_RUBY_DEBUG_LOG=1', with: { cppflags: '-DUSE_RUBY_DEBUG_LOG=1' }, timeout-minutes: 8 } - { uses: './.github/actions/compilers', name: 'USE_DEBUG_COUNTER', with: { cppflags: '-DUSE_DEBUG_COUNTER=1' }, timeout-minutes: 8 } @@ -274,7 +290,7 @@ jobs: steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false } - - { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true, fetch-depth: 10 } } + - uses: './.github/actions/setup/compilation-source' - { uses: './.github/actions/compilers', name: 'GC_DEBUG_STRESS_TO_CLASS', with: { cppflags: '-DGC_DEBUG_STRESS_TO_CLASS' }, timeout-minutes: 8 } - { uses: './.github/actions/compilers', name: 'GC_ENABLE_LAZY_SWEEP=0', with: { cppflags: '-DGC_ENABLE_LAZY_SWEEP=0' }, timeout-minutes: 8 } - { uses: './.github/actions/compilers', name: 'GC_PROFILE_DETAIL_MEMORY', with: { cppflags: '-DGC_PROFILE_DETAIL_MEMORY' }, timeout-minutes: 8 } @@ -293,7 +309,7 @@ jobs: steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false } - - { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true, fetch-depth: 10 } } + - uses: './.github/actions/setup/compilation-source' - { uses: './.github/actions/compilers', name: 'VM_DEBUG_BP_CHECK', with: { cppflags: '-DVM_DEBUG_BP_CHECK' }, timeout-minutes: 8 } - { uses: './.github/actions/compilers', name: 'VM_DEBUG_VERIFY_METHOD_CACHE', with: { cppflags: '-DVM_DEBUG_VERIFY_METHOD_CACHE' }, timeout-minutes: 8 } - { uses: './.github/actions/compilers', name: 'YJIT_FORCE_ENABLE', with: { cppflags: '-DYJIT_FORCE_ENABLE' }, timeout-minutes: 8 } @@ -328,6 +344,21 @@ jobs: label: 'omnibus' SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot if: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }} + + # Reduce retained artifact storage. + - name: Create empty source artifact + run: touch compilation-source.empty + working-directory: ${{ runner.temp }} + if: ${{ always() }} + - name: Shrink source artifact + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: compilation-source + path: ${{ runner.temp }}/compilation-source.empty + overwrite: true + retention-days: 1 + if: ${{ always() }} + - run: false working-directory: if: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }} From 5d201a91074d4249bf4edb9506d376163fff4773 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Mon, 17 Aug 2026 16:43:05 +0900 Subject: [PATCH 4/7] Rebalance Compilations jobs after sharing sources Keep the longest compiler jobs below 30 minutes after preparing sources once. --- .github/workflows/compilers.yml | 38 ++++++++++++++++----------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/.github/workflows/compilers.yml b/.github/workflows/compilers.yml index 6f77d2e95a94db..dfcb1b68ac774a 100644 --- a/.github/workflows/compilers.yml +++ b/.github/workflows/compilers.yml @@ -83,7 +83,11 @@ jobs: with_gcc: 'clang-23 -flto=auto' optflags: '-O2' timeout-minutes: 30 + - { uses: './.github/actions/compilers', name: 'clang 23', with: { tag: 'clang-23' }, timeout-minutes: 8 } + - { uses: './.github/actions/compilers', name: 'clang 22', with: { tag: 'clang-22' }, timeout-minutes: 8 } + - { uses: './.github/actions/compilers', name: 'clang 21', with: { tag: 'clang-21' }, timeout-minutes: 8 } - { uses: './.github/actions/compilers', name: '-O0', with: { optflags: '-O0 -march=x86-64 -mtune=generic' }, timeout-minutes: 8 } + - { uses: './.github/actions/compilers', name: 'YJIT_FORCE_ENABLE', with: { cppflags: '-DYJIT_FORCE_ENABLE' }, timeout-minutes: 8 } # - { uses: './.github/actions/compilers', name: '-O3', with: { optflags: '-O3 -march=x86-64 -mtune=generic', check: true } } compile2: @@ -105,14 +109,11 @@ jobs: optflags: '-O2' enable_shared: false timeout-minutes: 10 - - { uses: './.github/actions/compilers', name: 'ext/Setup', with: { static_exts: 'etc json/* */escape' }, timeout-minutes: 8 } - { uses: './.github/actions/compilers', name: 'GCC 15', with: { tag: 'gcc-15' }, timeout-minutes: 8 } - { uses: './.github/actions/compilers', name: 'GCC 14', with: { tag: 'gcc-14' }, timeout-minutes: 8 } - { uses: './.github/actions/compilers', name: 'GCC 13', with: { tag: 'gcc-13' }, timeout-minutes: 8 } - { uses: './.github/actions/compilers', name: 'GCC 12', with: { tag: 'gcc-12' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'GCC 11', with: { tag: 'gcc-11' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'GCC 10', with: { tag: 'gcc-10' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'GCC 9', with: { tag: 'gcc-9' }, timeout-minutes: 8 } + - { uses: './.github/actions/compilers', name: 'UNIVERSAL_PARSER', with: { cppflags: '-DUNIVERSAL_PARSER' }, timeout-minutes: 8 } compile3: name: 'omnibus compilations, #3' @@ -152,7 +153,6 @@ jobs: - { uses: './.github/actions/compilers', name: 'clang 9', with: { tag: 'clang-9', append_configure: '--disable-yjit --disable-zjit' }, timeout-minutes: 8 } - { uses: './.github/actions/compilers', name: 'clang 8', with: { tag: 'clang-8', append_configure: '--disable-yjit --disable-zjit' }, timeout-minutes: 8 } - { uses: './.github/actions/compilers', name: 'clang 7', with: { tag: 'clang-7', append_configure: '--disable-yjit --disable-zjit' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'clang 6', with: { tag: 'clang-6.0', append_configure: '--disable-yjit --disable-zjit' }, timeout-minutes: 8 } compile5: name: 'omnibus compilations, #5' @@ -178,7 +178,6 @@ jobs: - { uses: './.github/actions/compilers', name: 'C++98', with: { CXXFLAGS: '-std=c++98 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' }, timeout-minutes: 8 } - { uses: './.github/actions/compilers', name: 'C++11', with: { CXXFLAGS: '-std=c++11 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' }, timeout-minutes: 8 } - { uses: './.github/actions/compilers', name: 'C++14', with: { CXXFLAGS: '-std=c++14 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'C++17', with: { CXXFLAGS: '-std=c++17 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' }, timeout-minutes: 8 } compile6: name: 'omnibus compilations, #6' @@ -215,10 +214,11 @@ jobs: - { uses: './.github/actions/compilers', name: 'disable-yjit', with: { append_configure: '--disable-yjit' }, timeout-minutes: 8 } - { uses: './.github/actions/compilers', name: 'disable-zjit', with: { append_configure: '--disable-zjit' }, timeout-minutes: 8 } - { uses: './.github/actions/compilers', name: 'disable-dln', with: { append_configure: '--disable-dln' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'enable-mkmf-verbose', with: { append_configure: '--enable-mkmf-verbose' }, timeout-minutes: 8 } - { uses: './.github/actions/compilers', name: 'disable-rubygems', with: { append_configure: '--disable-rubygems' }, timeout-minutes: 8 } - { uses: './.github/actions/compilers', name: 'RUBY_DEVEL', with: { append_configure: '--enable-devel' }, timeout-minutes: 8 } - { uses: './.github/actions/compilers', name: 'OPT_THREADED_CODE=0', with: { cppflags: '-DOPT_THREADED_CODE=0' }, timeout-minutes: 8 } + - { uses: './.github/actions/compilers', name: 'OPT_THREADED_CODE=1', with: { cppflags: '-DOPT_THREADED_CODE=1' }, timeout-minutes: 8 } + - { uses: './.github/actions/compilers', name: 'OPT_THREADED_CODE=2', with: { cppflags: '-DOPT_THREADED_CODE=2' }, timeout-minutes: 8 } compile8: name: 'omnibus compilations, #8' @@ -237,7 +237,8 @@ jobs: - { uses: './.github/actions/compilers', name: 'CCAN_LIST_DEBUG', with: { cppflags: '-DCCAN_LIST_DEBUG' }, timeout-minutes: 8 } - { uses: './.github/actions/compilers', name: 'CPDEBUG=-1', with: { cppflags: '-DCPDEBUG=-1' }, timeout-minutes: 8 } - { uses: './.github/actions/compilers', name: 'ENC_DEBUG', with: { cppflags: '-DENC_DEBUG' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'GC_DEBUG', with: { cppflags: '-DGC_DEBUG' }, timeout-minutes: 8 } + - { uses: './.github/actions/compilers', name: 'VM_DEBUG_BP_CHECK', with: { cppflags: '-DVM_DEBUG_BP_CHECK' }, timeout-minutes: 8 } + - { uses: './.github/actions/compilers', name: 'VM_DEBUG_VERIFY_METHOD_CACHE', with: { cppflags: '-DVM_DEBUG_VERIFY_METHOD_CACHE' }, timeout-minutes: 8 } compile9: name: 'omnibus compilations, #9' @@ -250,7 +251,6 @@ jobs: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false } - uses: './.github/actions/setup/compilation-source' - - { uses: './.github/actions/compilers', name: 'HASH_DEBUG', with: { cppflags: '-DHASH_DEBUG' }, timeout-minutes: 8 } - { uses: './.github/actions/compilers', name: 'ID_TABLE_DEBUG', with: { cppflags: '-DID_TABLE_DEBUG' }, timeout-minutes: 8 } - { uses: './.github/actions/compilers', name: 'RGENGC_DEBUG=-1', with: { cppflags: '-DRGENGC_DEBUG=-1' }, timeout-minutes: 8 } - { uses: './.github/actions/compilers', name: 'SYMBOL_DEBUG', with: { cppflags: '-DSYMBOL_DEBUG' }, timeout-minutes: 8 } @@ -276,9 +276,7 @@ jobs: - { uses: './.github/actions/compilers', name: 'SHARABLE_MIDDLE_SUBSTRING', with: { cppflags: '-DSHARABLE_MIDDLE_SUBSTRING=1' }, timeout-minutes: 8 } - { uses: './.github/actions/compilers', name: 'DEBUG_FIND_TIME_NUMGUESS', with: { cppflags: '-DDEBUG_FIND_TIME_NUMGUESS' }, timeout-minutes: 8 } - { uses: './.github/actions/compilers', name: 'DEBUG_INTEGER_PACK', with: { cppflags: '-DDEBUG_INTEGER_PACK' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'OPT_THREADED_CODE=1', with: { cppflags: '-DOPT_THREADED_CODE=1' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'OPT_THREADED_CODE=2', with: { cppflags: '-DOPT_THREADED_CODE=2' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'clang 21', with: { tag: 'clang-21' }, timeout-minutes: 8 } + - { uses: './.github/actions/compilers', name: 'RGENGC_PROFILE', with: { cppflags: '-DRGENGC_PROFILE' }, timeout-minutes: 8 } compileB: name: 'omnibus compilations, #11' @@ -292,12 +290,13 @@ jobs: with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false } - uses: './.github/actions/setup/compilation-source' - { uses: './.github/actions/compilers', name: 'GC_DEBUG_STRESS_TO_CLASS', with: { cppflags: '-DGC_DEBUG_STRESS_TO_CLASS' }, timeout-minutes: 8 } + - { uses: './.github/actions/compilers', name: 'GC_DEBUG', with: { cppflags: '-DGC_DEBUG' }, timeout-minutes: 8 } - { uses: './.github/actions/compilers', name: 'GC_ENABLE_LAZY_SWEEP=0', with: { cppflags: '-DGC_ENABLE_LAZY_SWEEP=0' }, timeout-minutes: 8 } - { uses: './.github/actions/compilers', name: 'GC_PROFILE_DETAIL_MEMORY', with: { cppflags: '-DGC_PROFILE_DETAIL_MEMORY' }, timeout-minutes: 8 } - { uses: './.github/actions/compilers', name: 'GC_PROFILE_MORE_DETAIL', with: { cppflags: '-DGC_PROFILE_MORE_DETAIL' }, timeout-minutes: 8 } - { uses: './.github/actions/compilers', name: 'MALLOC_ALLOCATED_SIZE_CHECK', with: { cppflags: '-DMALLOC_ALLOCATED_SIZE_CHECK' }, timeout-minutes: 8 } - { uses: './.github/actions/compilers', name: 'RGENGC_ESTIMATE_OLDMALLOC', with: { cppflags: '-DRGENGC_ESTIMATE_OLDMALLOC' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'RGENGC_PROFILE', with: { cppflags: '-DRGENGC_PROFILE' }, timeout-minutes: 8 } + - { uses: './.github/actions/compilers', name: 'C++17', with: { CXXFLAGS: '-std=c++17 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' }, timeout-minutes: 8 } compileC: name: 'omnibus compilations, #12' @@ -310,14 +309,15 @@ jobs: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false } - uses: './.github/actions/setup/compilation-source' - - { uses: './.github/actions/compilers', name: 'VM_DEBUG_BP_CHECK', with: { cppflags: '-DVM_DEBUG_BP_CHECK' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'VM_DEBUG_VERIFY_METHOD_CACHE', with: { cppflags: '-DVM_DEBUG_VERIFY_METHOD_CACHE' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'YJIT_FORCE_ENABLE', with: { cppflags: '-DYJIT_FORCE_ENABLE' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'UNIVERSAL_PARSER', with: { cppflags: '-DUNIVERSAL_PARSER' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'clang 23', with: { tag: 'clang-23' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'clang 22', with: { tag: 'clang-22' }, timeout-minutes: 8 } + - { uses: './.github/actions/compilers', name: 'GCC 11', with: { tag: 'gcc-11' }, timeout-minutes: 8 } + - { uses: './.github/actions/compilers', name: 'GCC 10', with: { tag: 'gcc-10' }, timeout-minutes: 8 } + - { uses: './.github/actions/compilers', name: 'GCC 9', with: { tag: 'gcc-9' }, timeout-minutes: 8 } - { uses: './.github/actions/compilers', name: 'GCC 8', with: { tag: 'gcc-8' }, timeout-minutes: 8 } - { uses: './.github/actions/compilers', name: 'GCC 7', with: { tag: 'gcc-7' }, timeout-minutes: 8 } + - { uses: './.github/actions/compilers', name: 'ext/Setup', with: { static_exts: 'etc json/* */escape' }, timeout-minutes: 8 } + - { uses: './.github/actions/compilers', name: 'enable-mkmf-verbose', with: { append_configure: '--enable-mkmf-verbose' }, timeout-minutes: 8 } + - { uses: './.github/actions/compilers', name: 'HASH_DEBUG', with: { cppflags: '-DHASH_DEBUG' }, timeout-minutes: 8 } + - { uses: './.github/actions/compilers', name: 'clang 6', with: { tag: 'clang-6.0', append_configure: '--disable-yjit --disable-zjit' }, timeout-minutes: 8 } compilemax: name: 'omnibus compilations, result' From 96e291c75ce7b43a34dc9b66b93882b96afc5e61 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Tue, 18 Aug 2026 15:32:48 +0900 Subject: [PATCH 5/7] Run Compilations in smaller shards Split compiler configurations into smaller matrix shards so faster runners can pick up pending work. --- .github/workflows/compilers.yml | 374 ++++++++++++-------------------- 1 file changed, 135 insertions(+), 239 deletions(-) diff --git a/.github/workflows/compilers.yml b/.github/workflows/compilers.yml index dfcb1b68ac774a..b89841ae1ca314 100644 --- a/.github/workflows/compilers.yml +++ b/.github/workflows/compilers.yml @@ -65,277 +65,173 @@ jobs: compression-level: 0 retention-days: 1 - compile1: - name: 'omnibus compilations, #1' - runs-on: ubuntu-latest + compile: + name: 'omnibus compilations, #${{ matrix.shard }}' needs: compile-if if: ${{ needs.compile-if.result == 'success' }} + strategy: + fail-fast: false + max-parallel: 12 + matrix: + shard: + - '01' + - '02' + - '03' + - '04' + - '05' + - '06' + - '07' + - '08' + - '09' + - '10' + - '11' + - '12' + - '13' + - '14' + - '15' + - '16' + - '17' + - '18' + - '19' + - '20' + - '21' + - '22' + - '23' + - '24' + runs-on: ubuntu-latest timeout-minutes: 60 steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false } - uses: './.github/actions/setup/compilation-source' + - name: 'clang 23 LTO' - uses: './.github/actions/compilers' + uses: &compilers './.github/actions/compilers' with: tag: clang-23 with_gcc: 'clang-23 -flto=auto' optflags: '-O2' timeout-minutes: 30 - - { uses: './.github/actions/compilers', name: 'clang 23', with: { tag: 'clang-23' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'clang 22', with: { tag: 'clang-22' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'clang 21', with: { tag: 'clang-21' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: '-O0', with: { optflags: '-O0 -march=x86-64 -mtune=generic' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'YJIT_FORCE_ENABLE', with: { cppflags: '-DYJIT_FORCE_ENABLE' }, timeout-minutes: 8 } - # - { uses: './.github/actions/compilers', name: '-O3', with: { optflags: '-O3 -march=x86-64 -mtune=generic', check: true } } - - compile2: - name: 'omnibus compilations, #2' - runs-on: ubuntu-latest - needs: compile-if - if: ${{ needs.compile-if.result == 'success' }} - timeout-minutes: 60 + if: ${{ matrix.shard == '18' }} + - { uses: *compilers, name: 'clang 23', with: { tag: 'clang-23' }, timeout-minutes: 8, if: "${{ matrix.shard == '18' }}" } + - { uses: *compilers, name: 'clang 22', with: { tag: 'clang-22' }, timeout-minutes: 8, if: "${{ matrix.shard == '22' }}" } + - { uses: *compilers, name: 'clang 21', with: { tag: 'clang-21' }, timeout-minutes: 8, if: "${{ matrix.shard == '22' }}" } + - { uses: *compilers, name: '-O0', with: { optflags: '-O0 -march=x86-64 -mtune=generic' }, timeout-minutes: 8, if: "${{ matrix.shard == '22' }}" } + - { uses: *compilers, name: 'YJIT_FORCE_ENABLE', with: { cppflags: '-DYJIT_FORCE_ENABLE' }, timeout-minutes: 8, if: "${{ matrix.shard == '22' }}" } - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false } - - uses: './.github/actions/setup/compilation-source' - name: 'GCC 15 LTO' - uses: './.github/actions/compilers' + uses: *compilers with: tag: gcc-15 with_gcc: 'gcc-15 -flto=auto -ffat-lto-objects -Werror=lto-type-mismatch' optflags: '-O2' enable_shared: false timeout-minutes: 10 - - { uses: './.github/actions/compilers', name: 'GCC 15', with: { tag: 'gcc-15' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'GCC 14', with: { tag: 'gcc-14' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'GCC 13', with: { tag: 'gcc-13' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'GCC 12', with: { tag: 'gcc-12' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'UNIVERSAL_PARSER', with: { cppflags: '-DUNIVERSAL_PARSER' }, timeout-minutes: 8 } - - compile3: - name: 'omnibus compilations, #3' - runs-on: ubuntu-latest - needs: compile-if - if: ${{ needs.compile-if.result == 'success' }} - timeout-minutes: 60 - - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false } - - uses: './.github/actions/setup/compilation-source' - - { uses: './.github/actions/compilers', name: 'clang 20', with: { tag: 'clang-20' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'clang 19', with: { tag: 'clang-19' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'clang 18', with: { tag: 'clang-18' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'clang 17', with: { tag: 'clang-17' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'clang 16', with: { tag: 'clang-16' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'clang 15', with: { tag: 'clang-15' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'clang 14', with: { tag: 'clang-14' }, timeout-minutes: 8 } - - compile4: - name: 'omnibus compilations, #4' - runs-on: ubuntu-latest - needs: compile-if - if: ${{ needs.compile-if.result == 'success' }} - timeout-minutes: 60 - - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false } - - uses: './.github/actions/setup/compilation-source' - - { uses: './.github/actions/compilers', name: 'clang 13', with: { tag: 'clang-13' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'clang 12', with: { tag: 'clang-12' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'clang 11', with: { tag: 'clang-11' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'clang 10', with: { tag: 'clang-10' }, timeout-minutes: 8 } + if: ${{ matrix.shard == '23' }} + - { uses: *compilers, name: 'GCC 15', with: { tag: 'gcc-15' }, timeout-minutes: 8, if: "${{ matrix.shard == '23' }}" } + - { uses: *compilers, name: 'GCC 14', with: { tag: 'gcc-14' }, timeout-minutes: 8, if: "${{ matrix.shard == '08' }}" } + - { uses: *compilers, name: 'GCC 13', with: { tag: 'gcc-13' }, timeout-minutes: 8, if: "${{ matrix.shard == '08' }}" } + - { uses: *compilers, name: 'GCC 12', with: { tag: 'gcc-12' }, timeout-minutes: 8, if: "${{ matrix.shard == '08' }}" } + - { uses: *compilers, name: 'UNIVERSAL_PARSER', with: { cppflags: '-DUNIVERSAL_PARSER' }, timeout-minutes: 8, if: "${{ matrix.shard == '08' }}" } + + - { uses: *compilers, name: 'clang 20', with: { tag: 'clang-20' }, timeout-minutes: 8, if: "${{ matrix.shard == '13' }}" } + - { uses: *compilers, name: 'clang 19', with: { tag: 'clang-19' }, timeout-minutes: 8, if: "${{ matrix.shard == '13' }}" } + - { uses: *compilers, name: 'clang 18', with: { tag: 'clang-18' }, timeout-minutes: 8, if: "${{ matrix.shard == '13' }}" } + - { uses: *compilers, name: 'clang 17', with: { tag: 'clang-17' }, timeout-minutes: 8, if: "${{ matrix.shard == '07' }}" } + - { uses: *compilers, name: 'clang 16', with: { tag: 'clang-16' }, timeout-minutes: 8, if: "${{ matrix.shard == '07' }}" } + - { uses: *compilers, name: 'clang 15', with: { tag: 'clang-15' }, timeout-minutes: 8, if: "${{ matrix.shard == '07' }}" } + - { uses: *compilers, name: 'clang 14', with: { tag: 'clang-14' }, timeout-minutes: 8, if: "${{ matrix.shard == '07' }}" } + + - { uses: *compilers, name: 'clang 13', with: { tag: 'clang-13' }, timeout-minutes: 8, if: "${{ matrix.shard == '19' }}" } + - { uses: *compilers, name: 'clang 12', with: { tag: 'clang-12' }, timeout-minutes: 8, if: "${{ matrix.shard == '19' }}" } + - { uses: *compilers, name: 'clang 11', with: { tag: 'clang-11' }, timeout-minutes: 8, if: "${{ matrix.shard == '19' }}" } + - { uses: *compilers, name: 'clang 10', with: { tag: 'clang-10' }, timeout-minutes: 8, if: "${{ matrix.shard == '19' }}" } # llvm-objcopy<=9 doesn't have --wildcard. It compiles, but leaves Rust symbols in libyjit.o and fail `make test-leaked-globals`. - - { uses: './.github/actions/compilers', name: 'clang 9', with: { tag: 'clang-9', append_configure: '--disable-yjit --disable-zjit' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'clang 8', with: { tag: 'clang-8', append_configure: '--disable-yjit --disable-zjit' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'clang 7', with: { tag: 'clang-7', append_configure: '--disable-yjit --disable-zjit' }, timeout-minutes: 8 } - - compile5: - name: 'omnibus compilations, #5' - runs-on: ubuntu-latest - needs: compile-if - if: ${{ needs.compile-if.result == 'success' }} - timeout-minutes: 60 + - { uses: *compilers, name: 'clang 9', with: { tag: 'clang-9', append_configure: '--disable-yjit --disable-zjit' }, timeout-minutes: 8, if: "${{ matrix.shard == '24' }}" } + - { uses: *compilers, name: 'clang 8', with: { tag: 'clang-8', append_configure: '--disable-yjit --disable-zjit' }, timeout-minutes: 8, if: "${{ matrix.shard == '24' }}" } + - { uses: *compilers, name: 'clang 7', with: { tag: 'clang-7', append_configure: '--disable-yjit --disable-zjit' }, timeout-minutes: 8, if: "${{ matrix.shard == '24' }}" } - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false } - - uses: './.github/actions/setup/compilation-source' # -Wno-strict-prototypes is necessary with clang-15 or newer, since - # older autoconf prior to 2.72 generate functions without prototype - # and -pedantic now implies strict-prototypes. Disabling the error - # but leaving the warning generates a lot of noise from use of - # ANYARGS in rb_define_method() and friends. - # See: https://github.com/llvm/llvm-project/commit/11da1b53d8cd3507959022cd790d5a7ad4573d94 - - { uses: './.github/actions/compilers', name: 'C99', with: { CFLAGS: '-std=c99 -Werror=pedantic -pedantic-errors -Wno-strict-prototypes' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'C11', with: { CFLAGS: '-std=c11 -Werror=pedantic -pedantic-errors -Wno-strict-prototypes' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'C17', with: { CFLAGS: '-std=c17 -Werror=pedantic -pedantic-errors -Wno-strict-prototypes' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'C23', with: { CFLAGS: '-std=c2x -Werror=pedantic -pedantic-errors -Wno-strict-prototypes' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'C++98', with: { CXXFLAGS: '-std=c++98 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'C++11', with: { CXXFLAGS: '-std=c++11 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'C++14', with: { CXXFLAGS: '-std=c++14 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' }, timeout-minutes: 8 } - - compile6: - name: 'omnibus compilations, #6' - runs-on: ubuntu-latest - needs: compile-if - if: ${{ needs.compile-if.result == 'success' }} - timeout-minutes: 60 - - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false } - - uses: './.github/actions/setup/compilation-source' - - { uses: './.github/actions/compilers', name: 'C++20', with: { CXXFLAGS: '-std=c++20 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'C++23', with: { CXXFLAGS: '-std=c++23 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'C++26', with: { CXXFLAGS: '-std=c++26 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'gmp', with: { append_configure: '--with-gmp', test_all: 'ruby/test_bignum.rb', test_spec: "/github/workspace/src/spec/ruby/core/integer" }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'jemalloc', with: { append_configure: '--with-jemalloc' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'valgrind', with: { append_configure: '--with-valgrind' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'coroutine=ucontext', with: { append_configure: '--with-coroutine=ucontext' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'coroutine=pthread', with: { append_configure: '--with-coroutine=pthread' }, timeout-minutes: 8 } - - compile7: - name: 'omnibus compilations, #7' - runs-on: ubuntu-latest - needs: compile-if - if: ${{ needs.compile-if.result == 'success' }} - timeout-minutes: 60 - - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false } - - uses: './.github/actions/setup/compilation-source' - - { uses: './.github/actions/compilers', name: 'disable-jit', with: { append_configure: '--disable-yjit --disable-zjit' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'disable-yjit', with: { append_configure: '--disable-yjit' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'disable-zjit', with: { append_configure: '--disable-zjit' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'disable-dln', with: { append_configure: '--disable-dln' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'disable-rubygems', with: { append_configure: '--disable-rubygems' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'RUBY_DEVEL', with: { append_configure: '--enable-devel' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'OPT_THREADED_CODE=0', with: { cppflags: '-DOPT_THREADED_CODE=0' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'OPT_THREADED_CODE=1', with: { cppflags: '-DOPT_THREADED_CODE=1' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'OPT_THREADED_CODE=2', with: { cppflags: '-DOPT_THREADED_CODE=2' }, timeout-minutes: 8 } - - compile8: - name: 'omnibus compilations, #8' - runs-on: ubuntu-latest - needs: compile-if - if: ${{ needs.compile-if.result == 'success' }} - timeout-minutes: 60 - - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false } - - uses: './.github/actions/setup/compilation-source' - - { uses: './.github/actions/compilers', name: 'NDEBUG', with: { cppflags: '-DNDEBUG' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'RUBY_DEBUG', with: { cppflags: '-DRUBY_DEBUG' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'ARRAY_DEBUG', with: { cppflags: '-DARRAY_DEBUG' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'CCAN_LIST_DEBUG', with: { cppflags: '-DCCAN_LIST_DEBUG' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'CPDEBUG=-1', with: { cppflags: '-DCPDEBUG=-1' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'ENC_DEBUG', with: { cppflags: '-DENC_DEBUG' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'VM_DEBUG_BP_CHECK', with: { cppflags: '-DVM_DEBUG_BP_CHECK' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'VM_DEBUG_VERIFY_METHOD_CACHE', with: { cppflags: '-DVM_DEBUG_VERIFY_METHOD_CACHE' }, timeout-minutes: 8 } - - compile9: - name: 'omnibus compilations, #9' - runs-on: ubuntu-latest - needs: compile-if - if: ${{ needs.compile-if.result == 'success' }} - timeout-minutes: 60 + # older autoconf prior to 2.72 generate functions without prototype. + - { uses: *compilers, name: 'C99', with: { CFLAGS: '-std=c99 -Werror=pedantic -pedantic-errors -Wno-strict-prototypes' }, timeout-minutes: 8, if: "${{ matrix.shard == '12' }}" } + - { uses: *compilers, name: 'C11', with: { CFLAGS: '-std=c11 -Werror=pedantic -pedantic-errors -Wno-strict-prototypes' }, timeout-minutes: 8, if: "${{ matrix.shard == '12' }}" } + - { uses: *compilers, name: 'C17', with: { CFLAGS: '-std=c17 -Werror=pedantic -pedantic-errors -Wno-strict-prototypes' }, timeout-minutes: 8, if: "${{ matrix.shard == '12' }}" } + - { uses: *compilers, name: 'C23', with: { CFLAGS: '-std=c2x -Werror=pedantic -pedantic-errors -Wno-strict-prototypes' }, timeout-minutes: 8, if: "${{ matrix.shard == '12' }}" } + - { uses: *compilers, name: 'C++98', with: { CXXFLAGS: '-std=c++98 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' }, timeout-minutes: 8, if: "${{ matrix.shard == '20' }}" } + - { uses: *compilers, name: 'C++11', with: { CXXFLAGS: '-std=c++11 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' }, timeout-minutes: 8, if: "${{ matrix.shard == '20' }}" } + - { uses: *compilers, name: 'C++14', with: { CXXFLAGS: '-std=c++14 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' }, timeout-minutes: 8, if: "${{ matrix.shard == '20' }}" } + + - { uses: *compilers, name: 'C++20', with: { CXXFLAGS: '-std=c++20 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' }, timeout-minutes: 8, if: "${{ matrix.shard == '10' }}" } + - { uses: *compilers, name: 'C++23', with: { CXXFLAGS: '-std=c++23 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' }, timeout-minutes: 8, if: "${{ matrix.shard == '10' }}" } + - { uses: *compilers, name: 'C++26', with: { CXXFLAGS: '-std=c++26 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' }, timeout-minutes: 8, if: "${{ matrix.shard == '10' }}" } + - { uses: *compilers, name: 'gmp', with: { append_configure: '--with-gmp', test_all: 'ruby/test_bignum.rb', test_spec: '/github/workspace/src/spec/ruby/core/integer' }, timeout-minutes: 8, if: "${{ matrix.shard == '10' }}" } + - { uses: *compilers, name: 'jemalloc', with: { append_configure: '--with-jemalloc' }, timeout-minutes: 8, if: "${{ matrix.shard == '03' }}" } + - { uses: *compilers, name: 'valgrind', with: { append_configure: '--with-valgrind' }, timeout-minutes: 8, if: "${{ matrix.shard == '03' }}" } + - { uses: *compilers, name: 'coroutine=ucontext', with: { append_configure: '--with-coroutine=ucontext' }, timeout-minutes: 8, if: "${{ matrix.shard == '03' }}" } + - { uses: *compilers, name: 'coroutine=pthread', with: { append_configure: '--with-coroutine=pthread' }, timeout-minutes: 8, if: "${{ matrix.shard == '03' }}" } + + - { uses: *compilers, name: 'disable-jit', with: { append_configure: '--disable-yjit --disable-zjit' }, timeout-minutes: 8, if: "${{ matrix.shard == '02' }}" } + - { uses: *compilers, name: 'disable-yjit', with: { append_configure: '--disable-yjit' }, timeout-minutes: 8, if: "${{ matrix.shard == '02' }}" } + - { uses: *compilers, name: 'disable-zjit', with: { append_configure: '--disable-zjit' }, timeout-minutes: 8, if: "${{ matrix.shard == '02' }}" } + - { uses: *compilers, name: 'disable-dln', with: { append_configure: '--disable-dln' }, timeout-minutes: 8, if: "${{ matrix.shard == '02' }}" } + - { uses: *compilers, name: 'disable-rubygems', with: { append_configure: '--disable-rubygems' }, timeout-minutes: 8, if: "${{ matrix.shard == '02' }}" } + - { uses: *compilers, name: 'RUBY_DEVEL', with: { append_configure: '--enable-devel' }, timeout-minutes: 8, if: "${{ matrix.shard == '14' }}" } + - { uses: *compilers, name: 'OPT_THREADED_CODE=0', with: { cppflags: '-DOPT_THREADED_CODE=0' }, timeout-minutes: 8, if: "${{ matrix.shard == '14' }}" } + - { uses: *compilers, name: 'OPT_THREADED_CODE=1', with: { cppflags: '-DOPT_THREADED_CODE=1' }, timeout-minutes: 8, if: "${{ matrix.shard == '14' }}" } + - { uses: *compilers, name: 'OPT_THREADED_CODE=2', with: { cppflags: '-DOPT_THREADED_CODE=2' }, timeout-minutes: 8, if: "${{ matrix.shard == '14' }}" } + + - { uses: *compilers, name: 'NDEBUG', with: { cppflags: '-DNDEBUG' }, timeout-minutes: 8, if: "${{ matrix.shard == '15' }}" } + - { uses: *compilers, name: 'RUBY_DEBUG', with: { cppflags: '-DRUBY_DEBUG' }, timeout-minutes: 8, if: "${{ matrix.shard == '15' }}" } + - { uses: *compilers, name: 'ARRAY_DEBUG', with: { cppflags: '-DARRAY_DEBUG' }, timeout-minutes: 8, if: "${{ matrix.shard == '15' }}" } + - { uses: *compilers, name: 'CCAN_LIST_DEBUG', with: { cppflags: '-DCCAN_LIST_DEBUG' }, timeout-minutes: 8, if: "${{ matrix.shard == '15' }}" } + - { uses: *compilers, name: 'CPDEBUG=-1', with: { cppflags: '-DCPDEBUG=-1' }, timeout-minutes: 8, if: "${{ matrix.shard == '04' }}" } + - { uses: *compilers, name: 'ENC_DEBUG', with: { cppflags: '-DENC_DEBUG' }, timeout-minutes: 8, if: "${{ matrix.shard == '04' }}" } + - { uses: *compilers, name: 'VM_DEBUG_BP_CHECK', with: { cppflags: '-DVM_DEBUG_BP_CHECK' }, timeout-minutes: 8, if: "${{ matrix.shard == '04' }}" } + - { uses: *compilers, name: 'VM_DEBUG_VERIFY_METHOD_CACHE', with: { cppflags: '-DVM_DEBUG_VERIFY_METHOD_CACHE' }, timeout-minutes: 8, if: "${{ matrix.shard == '04' }}" } + + - { uses: *compilers, name: 'ID_TABLE_DEBUG', with: { cppflags: '-DID_TABLE_DEBUG' }, timeout-minutes: 8, if: "${{ matrix.shard == '17' }}" } + - { uses: *compilers, name: 'RGENGC_DEBUG=-1', with: { cppflags: '-DRGENGC_DEBUG=-1' }, timeout-minutes: 8, if: "${{ matrix.shard == '17' }}" } + - { uses: *compilers, name: 'SYMBOL_DEBUG', with: { cppflags: '-DSYMBOL_DEBUG' }, timeout-minutes: 8, if: "${{ matrix.shard == '17' }}" } + - { uses: *compilers, name: 'RGENGC_CHECK_MODE', with: { cppflags: '-DRGENGC_CHECK_MODE' }, timeout-minutes: 8, if: "${{ matrix.shard == '06' }}" } + - { uses: *compilers, name: 'VM_CHECK_MODE', with: { cppflags: '-DVM_CHECK_MODE' }, timeout-minutes: 8, if: "${{ matrix.shard == '06' }}" } + - { uses: *compilers, name: 'USE_EMBED_CI=0', with: { cppflags: '-DUSE_EMBED_CI=0' }, timeout-minutes: 8, if: "${{ matrix.shard == '06' }}" } + - { uses: *compilers, name: 'USE_FLONUM=0', with: { cppflags: '-DUSE_FLONUM=0', append_configure: '--disable-yjit --disable-zjit' }, timeout-minutes: 8, if: "${{ matrix.shard == '06' }}" } + + - { uses: *compilers, name: 'USE_LAZY_LOAD', with: { cppflags: '-DUSE_LAZY_LOAD' }, timeout-minutes: 8, if: "${{ matrix.shard == '05' }}" } + - { uses: *compilers, name: 'USE_RUBY_DEBUG_LOG=1', with: { cppflags: '-DUSE_RUBY_DEBUG_LOG=1' }, timeout-minutes: 8, if: "${{ matrix.shard == '05' }}" } + - { uses: *compilers, name: 'USE_DEBUG_COUNTER', with: { cppflags: '-DUSE_DEBUG_COUNTER=1' }, timeout-minutes: 8, if: "${{ matrix.shard == '05' }}" } + - { uses: *compilers, name: 'SHARABLE_MIDDLE_SUBSTRING', with: { cppflags: '-DSHARABLE_MIDDLE_SUBSTRING=1' }, timeout-minutes: 8, if: "${{ matrix.shard == '05' }}" } + - { uses: *compilers, name: 'DEBUG_FIND_TIME_NUMGUESS', with: { cppflags: '-DDEBUG_FIND_TIME_NUMGUESS' }, timeout-minutes: 8, if: "${{ matrix.shard == '16' }}" } + - { uses: *compilers, name: 'DEBUG_INTEGER_PACK', with: { cppflags: '-DDEBUG_INTEGER_PACK' }, timeout-minutes: 8, if: "${{ matrix.shard == '16' }}" } + - { uses: *compilers, name: 'RGENGC_PROFILE', with: { cppflags: '-DRGENGC_PROFILE' }, timeout-minutes: 8, if: "${{ matrix.shard == '16' }}" } + + - { uses: *compilers, name: 'GC_DEBUG_STRESS_TO_CLASS', with: { cppflags: '-DGC_DEBUG_STRESS_TO_CLASS' }, timeout-minutes: 8, if: "${{ matrix.shard == '21' }}" } + - { uses: *compilers, name: 'GC_DEBUG', with: { cppflags: '-DGC_DEBUG' }, timeout-minutes: 8, if: "${{ matrix.shard == '21' }}" } + - { uses: *compilers, name: 'GC_ENABLE_LAZY_SWEEP=0', with: { cppflags: '-DGC_ENABLE_LAZY_SWEEP=0' }, timeout-minutes: 8, if: "${{ matrix.shard == '21' }}" } + - { uses: *compilers, name: 'GC_PROFILE_DETAIL_MEMORY', with: { cppflags: '-DGC_PROFILE_DETAIL_MEMORY' }, timeout-minutes: 8, if: "${{ matrix.shard == '21' }}" } + - { uses: *compilers, name: 'GC_PROFILE_MORE_DETAIL', with: { cppflags: '-DGC_PROFILE_MORE_DETAIL' }, timeout-minutes: 8, if: "${{ matrix.shard == '09' }}" } + - { uses: *compilers, name: 'MALLOC_ALLOCATED_SIZE_CHECK', with: { cppflags: '-DMALLOC_ALLOCATED_SIZE_CHECK' }, timeout-minutes: 8, if: "${{ matrix.shard == '09' }}" } + - { uses: *compilers, name: 'RGENGC_ESTIMATE_OLDMALLOC', with: { cppflags: '-DRGENGC_ESTIMATE_OLDMALLOC' }, timeout-minutes: 8, if: "${{ matrix.shard == '09' }}" } + - { uses: *compilers, name: 'C++17', with: { CXXFLAGS: '-std=c++17 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' }, timeout-minutes: 8, if: "${{ matrix.shard == '09' }}" } + + - { uses: *compilers, name: 'GCC 11', with: { tag: 'gcc-11' }, timeout-minutes: 8, if: "${{ matrix.shard == '11' }}" } + - { uses: *compilers, name: 'GCC 10', with: { tag: 'gcc-10' }, timeout-minutes: 8, if: "${{ matrix.shard == '11' }}" } + - { uses: *compilers, name: 'GCC 9', with: { tag: 'gcc-9' }, timeout-minutes: 8, if: "${{ matrix.shard == '11' }}" } + - { uses: *compilers, name: 'GCC 8', with: { tag: 'gcc-8' }, timeout-minutes: 8, if: "${{ matrix.shard == '11' }}" } + - { uses: *compilers, name: 'GCC 7', with: { tag: 'gcc-7' }, timeout-minutes: 8, if: "${{ matrix.shard == '01' }}" } + - { uses: *compilers, name: 'ext/Setup', with: { static_exts: 'etc json/* */escape' }, timeout-minutes: 8, if: "${{ matrix.shard == '01' }}" } + - { uses: *compilers, name: 'enable-mkmf-verbose', with: { append_configure: '--enable-mkmf-verbose' }, timeout-minutes: 8, if: "${{ matrix.shard == '01' }}" } + - { uses: *compilers, name: 'HASH_DEBUG', with: { cppflags: '-DHASH_DEBUG' }, timeout-minutes: 8, if: "${{ matrix.shard == '01' }}" } + - { uses: *compilers, name: 'clang 6', with: { tag: 'clang-6.0', append_configure: '--disable-yjit --disable-zjit' }, timeout-minutes: 8, if: "${{ matrix.shard == '01' }}" } - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false } - - uses: './.github/actions/setup/compilation-source' - - { uses: './.github/actions/compilers', name: 'ID_TABLE_DEBUG', with: { cppflags: '-DID_TABLE_DEBUG' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'RGENGC_DEBUG=-1', with: { cppflags: '-DRGENGC_DEBUG=-1' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'SYMBOL_DEBUG', with: { cppflags: '-DSYMBOL_DEBUG' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'RGENGC_CHECK_MODE', with: { cppflags: '-DRGENGC_CHECK_MODE' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'VM_CHECK_MODE', with: { cppflags: '-DVM_CHECK_MODE' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'USE_EMBED_CI=0', with: { cppflags: '-DUSE_EMBED_CI=0' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'USE_FLONUM=0', with: { cppflags: '-DUSE_FLONUM=0', append_configure: '--disable-yjit --disable-zjit' }, timeout-minutes: 8 } - - compileX: - name: 'omnibus compilations, #10' - runs-on: ubuntu-latest - needs: compile-if - if: ${{ needs.compile-if.result == 'success' }} - timeout-minutes: 60 - - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false } - - uses: './.github/actions/setup/compilation-source' - - { uses: './.github/actions/compilers', name: 'USE_LAZY_LOAD', with: { cppflags: '-DUSE_LAZY_LOAD' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'USE_RUBY_DEBUG_LOG=1', with: { cppflags: '-DUSE_RUBY_DEBUG_LOG=1' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'USE_DEBUG_COUNTER', with: { cppflags: '-DUSE_DEBUG_COUNTER=1' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'SHARABLE_MIDDLE_SUBSTRING', with: { cppflags: '-DSHARABLE_MIDDLE_SUBSTRING=1' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'DEBUG_FIND_TIME_NUMGUESS', with: { cppflags: '-DDEBUG_FIND_TIME_NUMGUESS' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'DEBUG_INTEGER_PACK', with: { cppflags: '-DDEBUG_INTEGER_PACK' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'RGENGC_PROFILE', with: { cppflags: '-DRGENGC_PROFILE' }, timeout-minutes: 8 } - - compileB: - name: 'omnibus compilations, #11' - runs-on: ubuntu-latest - needs: compile-if - if: ${{ needs.compile-if.result == 'success' }} - timeout-minutes: 60 - - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false } - - uses: './.github/actions/setup/compilation-source' - - { uses: './.github/actions/compilers', name: 'GC_DEBUG_STRESS_TO_CLASS', with: { cppflags: '-DGC_DEBUG_STRESS_TO_CLASS' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'GC_DEBUG', with: { cppflags: '-DGC_DEBUG' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'GC_ENABLE_LAZY_SWEEP=0', with: { cppflags: '-DGC_ENABLE_LAZY_SWEEP=0' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'GC_PROFILE_DETAIL_MEMORY', with: { cppflags: '-DGC_PROFILE_DETAIL_MEMORY' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'GC_PROFILE_MORE_DETAIL', with: { cppflags: '-DGC_PROFILE_MORE_DETAIL' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'MALLOC_ALLOCATED_SIZE_CHECK', with: { cppflags: '-DMALLOC_ALLOCATED_SIZE_CHECK' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'RGENGC_ESTIMATE_OLDMALLOC', with: { cppflags: '-DRGENGC_ESTIMATE_OLDMALLOC' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'C++17', with: { CXXFLAGS: '-std=c++17 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' }, timeout-minutes: 8 } - - compileC: - name: 'omnibus compilations, #12' - runs-on: ubuntu-latest - needs: compile-if - if: ${{ needs.compile-if.result == 'success' }} - timeout-minutes: 60 - - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false } - - uses: './.github/actions/setup/compilation-source' - - { uses: './.github/actions/compilers', name: 'GCC 11', with: { tag: 'gcc-11' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'GCC 10', with: { tag: 'gcc-10' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'GCC 9', with: { tag: 'gcc-9' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'GCC 8', with: { tag: 'gcc-8' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'GCC 7', with: { tag: 'gcc-7' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'ext/Setup', with: { static_exts: 'etc json/* */escape' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'enable-mkmf-verbose', with: { append_configure: '--enable-mkmf-verbose' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'HASH_DEBUG', with: { cppflags: '-DHASH_DEBUG' }, timeout-minutes: 8 } - - { uses: './.github/actions/compilers', name: 'clang 6', with: { tag: 'clang-6.0', append_configure: '--disable-yjit --disable-zjit' }, timeout-minutes: 8 } compilemax: name: 'omnibus compilations, result' runs-on: ubuntu-latest if: ${{ always() }} needs: - - 'compile1' - - 'compile2' - - 'compile3' - - 'compile4' - - 'compile5' - - 'compile6' - - 'compile7' - - 'compile8' - - 'compile9' - - 'compileX' - - 'compileB' - - 'compileC' + - 'compile' steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github, persist-credentials: false } From 04b65bf41060821ac6ff07e2c8bd325b829a96ee Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Tue, 4 Aug 2026 13:49:56 +0900 Subject: [PATCH 6/7] [ruby/rubygems] Reject SafeMarshal collection lengths longer than the remaining input A crafted 4-byte length makes read_array and its siblings allocate the Array.new backing store before reading a single element, so an 8-byte payload can request gigabytes of memory (HackerOne 3877678, triaged as hardening). Since every element consumes at least one byte, a count larger than the remaining input bytes can never be valid. Raise the new LengthTooLongError instead of allocating, and add the negative length check that read_hash was missing. https://github.com/ruby/rubygems/commit/4c16744929 Co-Authored-By: Claude Fable 5 --- lib/rubygems/safe_marshal/reader.rb | 29 ++++++++++++++++-------- test/rubygems/test_gem_safe_marshal.rb | 31 ++++++++++++++++++++++++-- 2 files changed, 49 insertions(+), 11 deletions(-) diff --git a/lib/rubygems/safe_marshal/reader.rb b/lib/rubygems/safe_marshal/reader.rb index 4d5796f937030f..ac33f91988c934 100644 --- a/lib/rubygems/safe_marshal/reader.rb +++ b/lib/rubygems/safe_marshal/reader.rb @@ -26,6 +26,9 @@ class DataTooShortError < Error class NegativeLengthError < Error end + class LengthTooLongError < Error + end + def initialize(io) @io = io @object_links = {} @@ -93,6 +96,18 @@ def read_integer end end + # Reads an element count and validates it against the number of bytes + # remaining in the input, since each element to be read consumes at + # least one byte. This prevents allocating huge backing stores for + # maliciously crafted lengths that could never be satisfied. + def read_count + count = read_integer + raise NegativeLengthError if count < 0 + remaining = @io.size - @io.pos + raise LengthTooLongError, "expected #{count} elements, but only #{remaining} bytes remain" if count > remaining + count + end + def read_element type = read_byte case type @@ -172,9 +187,8 @@ def read_user_defined private_constant :EMPTY_ARRAY def read_array - length = read_integer + length = read_count return EMPTY_ARRAY if length == 0 - raise NegativeLengthError if length < 0 elements = Array.new(length) do read_element end @@ -183,8 +197,7 @@ def read_array def read_object_with_ivars object = read_element - length = read_integer - raise NegativeLengthError if length < 0 + length = read_count ivars = Array.new(length) do [read_element, read_element] end @@ -211,7 +224,7 @@ def read_object_link private_constant :EMPTY_HASH def read_hash - length = read_integer + length = read_count return EMPTY_HASH if length == 0 pairs = Array.new(length) do [read_element, read_element] @@ -220,8 +233,7 @@ def read_hash end def read_hash_with_default_value - length = read_integer - raise NegativeLengthError if length < 0 + length = read_count pairs = Array.new(length) do [read_element, read_element] end @@ -232,8 +244,7 @@ def read_hash_with_default_value def read_object name = read_element object = Elements::Object.new(name) - length = read_integer - raise NegativeLengthError if length < 0 + length = read_count ivars = Array.new(length) do [read_element, read_element] end diff --git a/test/rubygems/test_gem_safe_marshal.rb b/test/rubygems/test_gem_safe_marshal.rb index 3d11c1cb9f6eeb..1937c02be0cb5a 100644 --- a/test/rubygems/test_gem_safe_marshal.rb +++ b/test/rubygems/test_gem_safe_marshal.rb @@ -423,10 +423,10 @@ def test_unexpected_eof end assert_equal e.message, "Unexpected EOF" - e = assert_raise(Gem::SafeMarshal::Reader::EOFError) do + e = assert_raise(Gem::SafeMarshal::Reader::LengthTooLongError) do Gem::SafeMarshal.safe_load("\x04\x08[\x06") end - assert_equal e.message, "Unexpected EOF" + assert_equal e.message, "expected 1 elements, but only 0 bytes remain" e = assert_raise(Gem::SafeMarshal::Reader::EOFError) do Gem::SafeMarshal.safe_load("\004\010:\012") @@ -459,6 +459,33 @@ def test_negative_length assert_raise(Gem::SafeMarshal::Reader::EOFError) do Gem::SafeMarshal.safe_load("\004\010@\377") end + assert_raise(Gem::SafeMarshal::Reader::NegativeLengthError) do + Gem::SafeMarshal.safe_load("\004\010{\325") + end + end + + def test_length_too_long + huge_length = "\x04#{[2_000_000_000].pack("V")}".b + + assert_raise(Gem::SafeMarshal::Reader::LengthTooLongError) do + Gem::SafeMarshal.safe_load("\x04\x08[#{huge_length}") + end + assert_raise(Gem::SafeMarshal::Reader::LengthTooLongError) do + Gem::SafeMarshal.safe_load("\x04\x08{#{huge_length}") + end + assert_raise(Gem::SafeMarshal::Reader::LengthTooLongError) do + Gem::SafeMarshal.safe_load("\x04\x08}#{huge_length}") + end + assert_raise(Gem::SafeMarshal::Reader::LengthTooLongError) do + Gem::SafeMarshal.safe_load("\x04\x08I\"\x00#{huge_length}") + end + assert_raise(Gem::SafeMarshal::Reader::LengthTooLongError) do + Gem::SafeMarshal.safe_load("\x04\x08o:\x06C#{huge_length}") + end + + # lengths that fit within the remaining input still parse + assert_equal [1, 2, 3], Gem::SafeMarshal.safe_load("\x04\x08[\x08i\x06i\ai\x08") + assert_equal({ 1 => 2 }, Gem::SafeMarshal.safe_load("\x04\x08{\x06i\x06i\a")) end def test_date_user_defined_rejected From 53e139eb33ca9af6ba35b468716e01f028f4f795 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Tue, 4 Aug 2026 15:49:28 +0900 Subject: [PATCH 7/7] Marshal.load: Fix buffer overflow at overread of string body A custom IO whose `read` returns more bytes than requested makes the leftover copy in `r_bytes1_buffered` write past the end of `arg->buf`. 7455eb4c260 fixed the same overread only for `r_byte1_buffered`. --- marshal.c | 4 ++++ test/ruby/test_marshal.rb | 22 ++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/marshal.c b/marshal.c index f86e50faffcb31..3ad30efa7e8f2c 100644 --- a/marshal.c +++ b/marshal.c @@ -1487,6 +1487,10 @@ r_bytes1_buffered(long len, struct load_arg *arg) if (tmp_len > need_len) { buflen = tmp_len - need_len; + if (UNLIKELY(buflen > arg->bufsize)) { + arg->buf = ruby_sized_realloc_n(arg->buf, buflen, 1, arg->bufsize); + arg->bufsize = buflen; + } memcpy(arg->buf, RSTRING_PTR(tmp)+need_len, buflen); arg->buflen = buflen; } diff --git a/test/ruby/test_marshal.rb b/test/ruby/test_marshal.rb index 48a67e1dc5f208..84c00a6502c71b 100644 --- a/test/ruby/test_marshal.rb +++ b/test/ruby/test_marshal.rb @@ -953,6 +953,28 @@ def read(_len, _outbuf = nil) assert_equal([nil, nil], Marshal.load(input)) end + def test_load_overread_string_body + input = Struct.new(:bytes, :count) do + def initialize + super("\x04\x08[\x07".bytes, 0) + end + + def getbyte + bytes.shift + end + + def read(_len, _outbuf = nil) + self.count += 1 + case count + when 1 then "\"\x06" # TYPE_STRING, length 1 + when 2 then "a" + "0" * (1024 * 128) + end + end + end.new + + assert_equal(["a", nil], Marshal.load(input)) + end + def test_bignum_len_overflow assert_raise(ArgumentError) do Marshal.load("\x04\x08l+\x04\x00\x00\x00\x40")