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 e5c964ad39d4e5..b89841ae1ca314 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,282 +44,194 @@ jobs:
|| contains(github.event.pull_request.labels.*.name, 'Documentation')
|| (github.event.pull_request.user.login == 'dependabot[bot]')
)}}
- steps:
- - run: true
- working-directory:
-
- compile1:
- name: 'omnibus compilations, #1'
- runs-on: ubuntu-latest
- needs: compile-if
- if: ${{ needs.compile-if.result == 'success' }}
- timeout-minutes: 60
+ timeout-minutes: 10
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 } }
- - name: 'clang 22 LTO'
- uses: './.github/actions/compilers'
+ - 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:
- tag: clang-22
- with_gcc: 'clang-22 -flto=auto'
- optflags: '-O2'
- timeout-minutes: 30
- - { uses: './.github/actions/compilers', name: '-O0', with: { optflags: '-O0 -march=x86-64 -mtune=generic' }, timeout-minutes: 8 }
- # - { uses: './.github/actions/compilers', name: '-O3', with: { optflags: '-O3 -march=x86-64 -mtune=generic', check: true } }
+ name: compilation-source
+ path: ${{ runner.temp }}/compilation-source.tar
+ compression-level: 0
+ retention-days: 1
- compile2:
- name: 'omnibus compilations, #2'
- 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/directories', with: { srcdir: 'src', builddir: 'build', makeup: true, fetch-depth: 10 } }
+ - uses: './.github/actions/setup/compilation-source'
+
+ - name: 'clang 23 LTO'
+ uses: &compilers './.github/actions/compilers'
+ with:
+ tag: clang-23
+ with_gcc: 'clang-23 -flto=auto'
+ optflags: '-O2'
+ timeout-minutes: 30
+ 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' }}" }
+
- 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: '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 }
-
- compile3:
- name: 'omnibus compilations, #3'
- runs-on: ubuntu-latest
- needs: compile-if
- if: ${{ needs.compile-if.result == 'success' }}
- timeout-minutes: 60
+ 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' }}" }
- 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/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 }
+ - { 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' }}" }
- 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/directories', with: { srcdir: 'src', builddir: 'build', makeup: true, fetch-depth: 10 } }
- - { 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 }
+ - { 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 }
- - { uses: './.github/actions/compilers', name: 'clang 6', with: { tag: 'clang-6.0', append_configure: '--disable-yjit --disable-zjit' }, timeout-minutes: 8 }
+ - { 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' }}" }
- compile5:
- name: 'omnibus compilations, #5'
- 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/directories', with: { srcdir: 'src', builddir: 'build', makeup: true, fetch-depth: 10 } }
# -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 }
- - { uses: './.github/actions/compilers', name: 'C++17', with: { CXXFLAGS: '-std=c++17 -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' }, timeout-minutes: 8 }
+ # 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' }}" }
- compile6:
- name: 'omnibus compilations, #6'
- runs-on: ubuntu-latest
- needs: compile-if
- if: ${{ needs.compile-if.result == 'success' }}
- timeout-minutes: 60
+ - { 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' }}" }
- 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/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 }
+ - { 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' }}" }
- 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/directories', with: { srcdir: 'src', builddir: 'build', makeup: true, fetch-depth: 10 } }
- - { 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: '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 }
-
- 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/directories', with: { srcdir: 'src', builddir: 'build', makeup: true, fetch-depth: 10 } }
- - { 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: 'GC_DEBUG', with: { cppflags: '-DGC_DEBUG' }, timeout-minutes: 8 }
-
- compile9:
- name: 'omnibus compilations, #9'
- 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/directories', with: { srcdir: 'src', builddir: 'build', makeup: true, fetch-depth: 10 } }
- - { 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 }
- - { 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
+ - { 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' }}" }
- 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/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: '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: *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' }}" }
- compileB:
- name: 'omnibus compilations, #11'
- runs-on: ubuntu-latest
- needs: compile-if
- if: ${{ needs.compile-if.result == 'success' }}
- timeout-minutes: 60
+ - { 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' }}" }
- 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/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 }
- - { 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: *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' }}" }
- compileC:
- name: 'omnibus compilations, #12'
- runs-on: ubuntu-latest
- needs: compile-if
- if: ${{ needs.compile-if.result == 'success' }}
- timeout-minutes: 60
+ - { 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/directories', with: { srcdir: 'src', builddir: 'build', makeup: true, fetch-depth: 10 } }
- - { 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 8', with: { tag: 'gcc-8' }, timeout-minutes: 8 }
- - { uses: './.github/actions/compilers', name: 'GCC 7', with: { tag: 'gcc-7' }, 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 }
@@ -328,6 +240,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') }}
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
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/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")
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