diff --git a/.github/workflows/annocheck.yml b/.github/workflows/annocheck.yml index 25454f6abeb6fe..6f10fef9dd6996 100644 --- a/.github/workflows/annocheck.yml +++ b/.github/workflows/annocheck.yml @@ -68,7 +68,7 @@ jobs: - run: id working-directory: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: sparse-checkout-cone-mode: false sparse-checkout: /.github diff --git a/.github/workflows/auto_request_review.yml b/.github/workflows/auto_request_review.yml index 998a6ea58a2225..ca27244b46547b 100644 --- a/.github/workflows/auto_request_review.yml +++ b/.github/workflows/auto_request_review.yml @@ -13,7 +13,7 @@ jobs: if: ${{ github.repository == 'ruby/ruby' && github.base_ref == 'master' }} steps: - name: Request review based on files changes and/or groups the author belongs to - uses: necojackarc/auto-request-review@6a51cebffe2c084705d9a7b394abd802e0119633 # v0.12.0 + uses: necojackarc/auto-request-review@e89da1a8cd7c8c16d9de9c6e763290b6b0e3d424 # v0.13.0 with: # scope: public_repo token: ${{ secrets.MATZBOT_GITHUB_TOKEN }} diff --git a/.github/workflows/baseruby.yml b/.github/workflows/baseruby.yml index 860d74aa1aac0f..73294b86c05699 100644 --- a/.github/workflows/baseruby.yml +++ b/.github/workflows/baseruby.yml @@ -37,7 +37,7 @@ jobs: baseruby: name: BASERUBY - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 if: >- ${{!(false @@ -58,12 +58,12 @@ jobs: - ruby-3.2 steps: - - uses: ruby/setup-ruby@036ef458ddccddb148a2b9fb67e95a22fdbf728b # v1.160.0 + - uses: ruby/setup-ruby@f41e084df884422b269f4c01c3748a9df4431a75 # v1.236.0 with: ruby-version: ${{ matrix.ruby }} bundler: none - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: ./.github/actions/setup/ubuntu diff --git a/.github/workflows/bundled_gems.yml b/.github/workflows/bundled_gems.yml index 943140e9ef9713..a40e2049779d9f 100644 --- a/.github/workflows/bundled_gems.yml +++ b/.github/workflows/bundled_gems.yml @@ -35,7 +35,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: token: ${{ (github.repository == 'ruby/ruby' && !startsWith(github.event_name, 'pull')) && secrets.MATZBOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/check_dependencies.yml b/.github/workflows/check_dependencies.yml index 37b993514685af..8fe60b6d220b7e 100644 --- a/.github/workflows/check_dependencies.yml +++ b/.github/workflows/check_dependencies.yml @@ -52,7 +52,7 @@ jobs: )}} steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: ./.github/actions/setup/ubuntu if: ${{ contains(matrix.os, 'ubuntu') }} diff --git a/.github/workflows/check_misc.yml b/.github/workflows/check_misc.yml index ce4397b35aac02..18b174d47cef23 100644 --- a/.github/workflows/check_misc.yml +++ b/.github/workflows/check_misc.yml @@ -18,7 +18,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: token: ${{ (github.repository == 'ruby/ruby' && !startsWith(github.event_name, 'pull')) && secrets.MATZBOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 47104672fe100b..2183e046b6a22d 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -56,7 +56,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Install libraries uses: ./.github/actions/setup/ubuntu @@ -70,6 +70,7 @@ jobs: uses: github/codeql-action/init@cdcdbb579706841c47f7063dda365e292e5cad7a # v2.13.4 with: languages: ${{ matrix.language }} + trap-caching: false - name: Autobuild uses: github/codeql-action/autobuild@cdcdbb579706841c47f7063dda365e292e5cad7a # v2.13.4 @@ -86,7 +87,7 @@ jobs: continue-on-error: true - name: filter-sarif - uses: advanced-security/filter-sarif@f3b8118a9349d88f7b1c0c488476411145b6270d # v1.0 + uses: advanced-security/filter-sarif@bc96d9fb9338c5b48cc440b1b4d0a350b26a20db # v1.0.0 with: patterns: | +**/*.rb diff --git a/.github/workflows/compilers.yml b/.github/workflows/compilers.yml index c00674c410529d..da44e4b21d7361 100644 --- a/.github/workflows/compilers.yml +++ b/.github/workflows/compilers.yml @@ -75,6 +75,8 @@ jobs: env: - {} entry: + - { name: gcc-15, env: { default_cc: gcc-15 } } + - { name: gcc-14, env: { default_cc: gcc-14 } } - { name: gcc-13, env: { default_cc: gcc-13 } } - { name: gcc-12, env: { default_cc: gcc-12 } } - { name: gcc-11, env: { default_cc: gcc-11 } } diff --git a/.github/workflows/dependabot_automerge.yml b/.github/workflows/dependabot_automerge.yml index 6259199b113b64..40e39d69247b9c 100644 --- a/.github/workflows/dependabot_automerge.yml +++ b/.github/workflows/dependabot_automerge.yml @@ -11,11 +11,11 @@ jobs: steps: - name: Dependabot metadata - uses: dependabot/fetch-metadata@c9c4182bf1b97f5224aee3906fd373f6b61b4526 # v1.6.0 + uses: dependabot/fetch-metadata@d7267f607e9d3fb96fc2fbe83e0af444713e90b7 # v2.3.0 id: metadata - name: Wait for status checks - uses: lewagon/wait-on-check-action@e106e5c43e8ca1edea6383a39a01c5ca495fd812 # v1.3.1 + uses: lewagon/wait-on-check-action@ccfb013c15c8afb7bf2b7c028fb74dc5a068cccc # v1.3.4 with: repo-token: ${{ secrets.MATZBOT_GITHUB_TOKEN }} ref: ${{ github.event.pull_request.head.sha || github.sha }} diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index fc98b09f5fd2ee..ff4bb203fadac7 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -53,7 +53,7 @@ jobs: )}} steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: sparse-checkout-cone-mode: false sparse-checkout: /.github diff --git a/.github/workflows/mingw.yml b/.github/workflows/mingw.yml index df879f56b6b353..92f24992e0d9ce 100644 --- a/.github/workflows/mingw.yml +++ b/.github/workflows/mingw.yml @@ -74,7 +74,7 @@ jobs: steps: - name: Set up Ruby & MSYS2 - uses: ruby/setup-ruby@036ef458ddccddb148a2b9fb67e95a22fdbf728b # v1.160.0 + uses: ruby/setup-ruby@f41e084df884422b269f4c01c3748a9df4431a75 # v1.236.0 with: ruby-version: ${{ matrix.base_ruby }} @@ -105,7 +105,7 @@ jobs: $result working-directory: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: sparse-checkout-cone-mode: false sparse-checkout: /.github diff --git a/.github/workflows/rjit-bindgen.yml b/.github/workflows/rjit-bindgen.yml index bf3c752e7b55cf..79b191580fd4e4 100644 --- a/.github/workflows/rjit-bindgen.yml +++ b/.github/workflows/rjit-bindgen.yml @@ -40,7 +40,7 @@ jobs: - task: rjit-bindgen fail-fast: false - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 if: >- ${{!(false @@ -52,11 +52,11 @@ jobs: steps: - name: Set up Ruby - uses: ruby/setup-ruby@036ef458ddccddb148a2b9fb67e95a22fdbf728b # v1.160.0 + uses: ruby/setup-ruby@f41e084df884422b269f4c01c3748a9df4431a75 # v1.236.0 with: ruby-version: '3.1' - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: sparse-checkout-cone-mode: false sparse-checkout: /.github diff --git a/.github/workflows/rjit.yml b/.github/workflows/rjit.yml index bf9122f5810494..7f2e82996e10f7 100644 --- a/.github/workflows/rjit.yml +++ b/.github/workflows/rjit.yml @@ -61,7 +61,7 @@ jobs: )}} steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: sparse-checkout-cone-mode: false sparse-checkout: /.github diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 51ce54a5181bfc..54694b0d4d621c 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -32,12 +32,12 @@ jobs: steps: - name: 'Checkout code' - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: persist-credentials: false - name: 'Run analysis' - uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1 + uses: ossf/scorecard-action@ea651e62978af7915d09fe2e282747c798bf2dab # v2.4.1 with: results_file: results.sarif results_format: sarif @@ -59,7 +59,7 @@ jobs: # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF # format to the repository Actions tab. # - name: "Upload artifact" - # uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2 + # uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 # with: # name: SARIF file # path: results.sarif diff --git a/.github/workflows/spec_guards.yml b/.github/workflows/spec_guards.yml index e14e7818a6c02b..ecf2264d100573 100644 --- a/.github/workflows/spec_guards.yml +++ b/.github/workflows/spec_guards.yml @@ -25,7 +25,7 @@ jobs: rubyspec: name: Rubyspec - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 if: >- ${{!(false @@ -45,9 +45,9 @@ jobs: - ruby-3.2 steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - uses: ruby/setup-ruby@036ef458ddccddb148a2b9fb67e95a22fdbf728b # v1.160.0 + - uses: ruby/setup-ruby@f41e084df884422b269f4c01c3748a9df4431a75 # v1.236.0 with: ruby-version: ${{ matrix.ruby }} bundler: none diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 93ced0d1d21f34..599cbf11337d14 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -50,7 +50,7 @@ jobs: GITPULLOPTIONS: --no-tags origin ${{ github.ref }} RUBY_DEBUG: ci - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 if: >- ${{!(false @@ -61,7 +61,7 @@ jobs: )}} steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: sparse-checkout-cone-mode: false sparse-checkout: /.github diff --git a/.github/workflows/wasm.yml b/.github/workflows/wasm.yml index 543b7d963c1025..dd5493528cc3e0 100644 --- a/.github/workflows/wasm.yml +++ b/.github/workflows/wasm.yml @@ -55,7 +55,7 @@ jobs: BINARYEN_VERSION: 113 WASMTIME_VERSION: v15.0.0 - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 if: >- ${{!(false @@ -66,7 +66,7 @@ jobs: )}} steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: sparse-checkout-cone-mode: false sparse-checkout: /.github @@ -114,6 +114,12 @@ jobs: make make install + - name: Download config.guess with wasi version + run: | + rm tool/config.guess tool/config.sub + ruby tool/downloader.rb -d tool -e gnu config.guess config.sub + working-directory: src + - name: Run configure run: | ../src/configure \ @@ -136,7 +142,7 @@ jobs: - run: tar cfz ../install.tar.gz -C ../install . - name: Upload artifacts - uses: actions/upload-artifact@604373da6381bf24206979c74d06a550515601b9 # v4.4.1 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: ruby-wasm-install path: ${{ github.workspace }}/install.tar.gz diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index cdbaf88c58eeb6..164c8c8624207f 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -37,11 +37,11 @@ jobs: strategy: matrix: include: - - vs: 2019 - # - vs: 2022 + - vs: 2022 + vcvers: -vcvars_ver=14.2 fail-fast: false - runs-on: windows-${{ matrix.vs < 2022 && '2019' || matrix.vs }} + runs-on: windows-${{ matrix.vs }} if: >- ${{!(false @@ -55,7 +55,7 @@ jobs: env: GITPULLOPTIONS: --no-tags origin ${{ github.ref }} - OS_VER: windows-${{ matrix.vs < 2022 && '2019' || matrix.vs }} + OS_VER: windows-${{ matrix.vs }} # FIXME: This is a workaround for the vcpkg's issue present as of openssl 3.1.1 # where OpenSSL's default modules directory is incorrectly set to C:\vcpkg\packages\openssl_x64-windows\bin # cf. https://github.com/ruby/openssl/pull/635#issuecomment-1596833720 @@ -85,7 +85,7 @@ jobs: NEEDED_TOOLS: >- patch.exe - - uses: msys2/setup-msys2@d40200dc2db4c351366b048a9565ad82919e1c24 # v2 + - uses: msys2/setup-msys2@61f9e5e925871ba6c9e3e8da24ede83ea27fa91f # v2.27.0 id: setup-msys2 with: update: true @@ -93,15 +93,7 @@ jobs: ${{ steps.find-tools.outputs.needs }} if: ${{ steps.find-tools.outputs.needs != '' }} - - uses: actions/cache@0c907a75c2c80ebcb7f088228285e798b750cf8f # v4.2.1 - with: - path: C:\vcpkg\downloads - key: ${{ runner.os }}-vcpkg-download-${{ env.OS_VER }}-${{ github.sha }} - restore-keys: | - ${{ runner.os }}-vcpkg-download-${{ env.OS_VER }}- - ${{ runner.os }}-vcpkg-download- - - - uses: actions/cache@0c907a75c2c80ebcb7f088228285e798b750cf8f # v4.2.1 + - uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 with: path: C:\vcpkg\installed key: ${{ runner.os }}-vcpkg-installed-${{ env.OS_VER }}-${{ github.sha }} @@ -109,18 +101,18 @@ jobs: ${{ runner.os }}-vcpkg-installed-${{ env.OS_VER }}- ${{ runner.os }}-vcpkg-installed- - - name: Install libraries with vcpkg - run: | - vcpkg --triplet x64-windows install libffi libyaml openssl readline zlib - - name: Install libraries with scoop run: | iex "& {$(irm get.scoop.sh)} -RunAsAdmin" Join-Path (Resolve-Path ~).Path "scoop\shims" >> $Env:GITHUB_PATH - scoop install vcpkg cmake@3.31.6 + scoop install cmake@3.31.6 shell: pwsh - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - name: Install libraries with vcpkg + run: | + vcpkg --triplet x64-windows install libffi libyaml openssl readline zlib + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: sparse-checkout-cone-mode: false sparse-checkout: /.github @@ -134,14 +126,12 @@ jobs: # %TEMP% is inconsistent with %TMP% and test-all expects they are consistent. # https://github.com/actions/virtual-environments/issues/712#issuecomment-613004302 run: | - set VS=${{ matrix.vs }} - set VCVARS=${{ matrix.vcvars || '' }} if not "%VCVARS%" == "" goto :vcset - set VCVARS="C:\Program Files (x86)\Microsoft Visual Studio\%VS%\Enterprise\VC\Auxiliary\Build\vcvars64.bat" - if not exist %VCVARS% set VCVARS="C:\Program Files\Microsoft Visual Studio\%VS%\Enterprise\VC\Auxiliary\Build\vcvars64.bat" + set VCVARS="C:\Program Files (x86)\Microsoft Visual Studio\${{ matrix.vs }}\Enterprise\VC\Auxiliary\Build\vcvars64.bat" + if not exist %VCVARS% set VCVARS="C:\Program Files\Microsoft Visual Studio\${{ matrix.vs }}\Enterprise\VC\Auxiliary\Build\vcvars64.bat" :vcset set | C:\msys64\usr\bin\sort > old.env - call %VCVARS% + call %VCVARS% ${{ matrix.vcvers || ''}} nmake -f nul set TMP=%USERPROFILE%\AppData\Local\Temp set TEMP=%USERPROFILE%\AppData\Local\Temp diff --git a/.github/workflows/yjit-macos.yml b/.github/workflows/yjit-macos.yml index 49fff17ae9c880..0718fe2783a10f 100644 --- a/.github/workflows/yjit-macos.yml +++ b/.github/workflows/yjit-macos.yml @@ -43,7 +43,7 @@ jobs: )}} steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - run: RUST_BACKTRACE=1 cargo test working-directory: yjit @@ -84,7 +84,7 @@ jobs: )}} steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: sparse-checkout-cone-mode: false sparse-checkout: /.github diff --git a/.github/workflows/yjit-ubuntu.yml b/.github/workflows/yjit-ubuntu.yml index ec8483b7d1281d..b9ed80a8dcb74f 100644 --- a/.github/workflows/yjit-ubuntu.yml +++ b/.github/workflows/yjit-ubuntu.yml @@ -32,7 +32,7 @@ jobs: name: cargo test # GitHub Action's image seems to already contain a Rust 1.58.0. - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 if: >- ${{!(false @@ -43,7 +43,7 @@ jobs: )}} steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 # For now we can't run cargo test --offline because it complains about the # capstone dependency, even though the dependency is optional @@ -64,7 +64,7 @@ jobs: name: cargo clippy # GitHub Action's image seems to already contain a Rust 1.58.0. - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 if: >- ${{!(false @@ -75,7 +75,7 @@ jobs: )}} steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 # Check that we don't have linting errors in release mode, too - run: cargo clippy --all-targets --all-features @@ -88,7 +88,8 @@ jobs: include: - test_task: 'yjit-bindgen' hint: 'To fix: use patch in logs' - configure: '--with-gcc=clang-12 --enable-yjit=dev' + configure: '--with-gcc=clang-14 --enable-yjit=dev' + libclang_path: '/usr/lib/llvm-14/lib/libclang.so.1' - test_task: 'check' # YJIT should be automatically built in release mode on x86-64 Linux with rustc present @@ -118,7 +119,7 @@ jobs: BUNDLE_JOBS: 8 # for yjit-bench RUST_BACKTRACE: 1 - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 if: >- ${{!(false @@ -129,7 +130,7 @@ jobs: )}} steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: sparse-checkout-cone-mode: false sparse-checkout: /.github @@ -173,6 +174,7 @@ jobs: PRECHECK_BUNDLED_GEMS: 'no' SYNTAX_SUGGEST_TIMEOUT: '5' YJIT_BINDGEN_DIFF_OPTS: '--exit-code' + LIBCLANG_PATH: ${{ matrix.libclang_path }} continue-on-error: ${{ matrix.test_task == 'yjit-bench' }} - name: Show ${{ github.event.pull_request.base.ref }} GitHub URL for yjit-bench comparison diff --git a/bignum.c b/bignum.c index e9bf37d2060ea7..bc48697bf4ad4f 100644 --- a/bignum.c +++ b/bignum.c @@ -6333,7 +6333,7 @@ bigand_int(VALUE x, long xn, BDIGIT hibitsx, long y) BDIGIT hibitsy; if (y == 0) return INT2FIX(0); - if (xn == 0) return hibitsx ? LONG2NUM(y) : 0; + if (xn == 0) return hibitsx ? LONG2NUM(y) : INT2FIX(0); hibitsy = 0 <= y ? 0 : BDIGMAX; xds = BDIGITS(x); #if SIZEOF_BDIGIT >= SIZEOF_LONG diff --git a/bootstraptest/test_ractor.rb b/bootstraptest/test_ractor.rb index ea7c2c197d4048..c03fbb07d7577d 100644 --- a/bootstraptest/test_ractor.rb +++ b/bootstraptest/test_ractor.rb @@ -1773,3 +1773,15 @@ class C8; def self.foo = 17; end } end # if !ENV['GITHUB_WORKFLOW'] + +# Using Symbol#to_proc inside ractors +# [Bug #21354] +assert_equal 'ok', %q{ + :inspect.to_proc + Ractor.new do + # It should not use this cached proc, it should create a new one. If it used + # the cached proc, we would get a ractor_confirm_belonging error here. + :inspect.to_proc + end.take + 'ok' +} diff --git a/bootstraptest/test_yjit.rb b/bootstraptest/test_yjit.rb index 31b9aabf11b7f2..02767a53bd81e6 100644 --- a/bootstraptest/test_yjit.rb +++ b/bootstraptest/test_yjit.rb @@ -3491,6 +3491,74 @@ def foo test } +# Bug #21257 (infinite jmp) +assert_equal 'ok', %q{ + Good = :ok + + def first + second + end + + def second + ::Good + end + + # Make `second` side exit on its first instruction + trace = TracePoint.new(:line) { } + trace.enable(target: method(:second)) + + first + # Recompile now that the constant cache is populated, so we get a fallthrough from `first` to `second` + # (this is need to reproduce with --yjit-call-threshold=1) + RubyVM::YJIT.code_gc if defined?(RubyVM::YJIT) + first + + # Trigger a constant cache miss in rb_vm_opt_getconstant_path (in `second`) next time it's called + module InvalidateConstantCache + Good = nil + end + + RubyVM::YJIT.simulate_oom! if defined?(RubyVM::YJIT) + + first + first +} + +assert_equal 'ok', %q{ + # Multiple incoming branches into second + Good = :ok + + def incoming_one + second + end + + def incoming_two + second + end + + def second + ::Good + end + + # Make `second` side exit on its first instruction + trace = TracePoint.new(:line) { } + trace.enable(target: method(:second)) + + incoming_one + # Recompile now that the constant cache is populated, so we get a fallthrough from `incoming_one` to `second` + # (this is need to reproduce with --yjit-call-threshold=1) + RubyVM::YJIT.code_gc if defined?(RubyVM::YJIT) + incoming_one + incoming_two + + # Trigger a constant cache miss in rb_vm_opt_getconstant_path (in `second`) next time it's called + module InvalidateConstantCache + Good = nil + end + + incoming_one +} + assert_equal 'ok', %q{ # Try to compile new method while OOM def foo diff --git a/common.mk b/common.mk index fe8c5ed74349fd..8075d6a95ec761 100644 --- a/common.mk +++ b/common.mk @@ -46,7 +46,7 @@ RUN_OPTS = --disable-gems # GITPULLOPTIONS = --no-tags PRISM_SRCDIR = $(srcdir)/prism -INCFLAGS = -I. -I$(arch_hdrdir) -I$(hdrdir) -I$(srcdir) -I$(PRISM_SRCDIR) -I$(UNICODE_HDR_DIR) $(incflags) +INCFLAGS = -I. -I$(arch_hdrdir) -I$(ext_hdrdir) -I$(hdrdir) -I$(srcdir) -I$(PRISM_SRCDIR) -I$(UNICODE_HDR_DIR) $(incflags) GEM_HOME = GEM_PATH = @@ -835,6 +835,12 @@ clean-platform distclean-platform realclean-platform: -$(Q) $(RMDIR) $(PLATFORM_DIR) 2> $(NULL) || $(NULLCMD) RUBYSPEC_CAPIEXT = spec/ruby/optional/capi/ext +RUBYSPEC_CAPIEXT_SRCDIR = $(srcdir)/$(RUBYSPEC_CAPIEXT) +RUBYSPEC_CAPIEXT_DEPS = $(RUBYSPEC_CAPIEXT_SRCDIR)/rubyspec.h $(RUBY_H_INCLUDES) $(LIBRUBY) + +rubyspec-capiext: build-ext $(DOT_WAIT) +# make-dependent rules should be included after this and built after build-ext. + clean-spec: PHONY -$(Q) $(RM) $(RUBYSPEC_CAPIEXT)/*.$(OBJEXT) $(RUBYSPEC_CAPIEXT)/*.$(DLEXT) -$(Q) $(RMDIRS) $(RUBYSPEC_CAPIEXT) 2> $(NULL) || $(NULLCMD) @@ -7503,6 +7509,7 @@ goruby.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h goruby.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h goruby.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h goruby.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h +goruby.$(OBJEXT): {$(VPATH)}internal/attr/nonstring.h goruby.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h goruby.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h goruby.$(OBJEXT): {$(VPATH)}internal/attr/pure.h @@ -9523,6 +9530,7 @@ marshal.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h marshal.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h marshal.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h marshal.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h +marshal.$(OBJEXT): {$(VPATH)}internal/attr/nonstring.h marshal.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h marshal.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h marshal.$(OBJEXT): {$(VPATH)}internal/attr/pure.h @@ -10132,6 +10140,7 @@ miniinit.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h miniinit.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h miniinit.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h miniinit.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h +miniinit.$(OBJEXT): {$(VPATH)}internal/attr/nonstring.h miniinit.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h miniinit.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h miniinit.$(OBJEXT): {$(VPATH)}internal/attr/pure.h @@ -12801,6 +12810,8 @@ proc.$(OBJEXT): {$(VPATH)}prism/ast.h proc.$(OBJEXT): {$(VPATH)}prism/version.h proc.$(OBJEXT): {$(VPATH)}prism_compile.h proc.$(OBJEXT): {$(VPATH)}proc.c +proc.$(OBJEXT): {$(VPATH)}ractor.h +proc.$(OBJEXT): {$(VPATH)}ractor_core.h proc.$(OBJEXT): {$(VPATH)}ruby_assert.h proc.$(OBJEXT): {$(VPATH)}ruby_atomic.h proc.$(OBJEXT): {$(VPATH)}rubyparser.h @@ -16467,6 +16478,7 @@ signal.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h signal.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h signal.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h signal.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h +signal.$(OBJEXT): {$(VPATH)}internal/attr/nonstring.h signal.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h signal.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h signal.$(OBJEXT): {$(VPATH)}internal/attr/pure.h @@ -17226,6 +17238,7 @@ string.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h string.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h string.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h string.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h +string.$(OBJEXT): {$(VPATH)}internal/attr/nonstring.h string.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h string.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h string.$(OBJEXT): {$(VPATH)}internal/attr/pure.h @@ -17684,6 +17697,7 @@ symbol.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h symbol.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h symbol.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h symbol.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h +symbol.$(OBJEXT): {$(VPATH)}internal/attr/nonstring.h symbol.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h symbol.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h symbol.$(OBJEXT): {$(VPATH)}internal/attr/pure.h diff --git a/compile.c b/compile.c index 110530f89f3c4a..22eadc8d25974b 100644 --- a/compile.c +++ b/compile.c @@ -9783,7 +9783,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no if (nd_fl_newline(node)) { int event = RUBY_EVENT_LINE; ISEQ_COMPILE_DATA(iseq)->last_line = line; - if (ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq)) { + if (line > 0 && ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq)) { event |= RUBY_EVENT_COVERAGE_LINE; } ADD_TRACE(ret, event); diff --git a/configure.ac b/configure.ac index 3b5ea5bade85bc..0f9553ee429158 100644 --- a/configure.ac +++ b/configure.ac @@ -1210,8 +1210,6 @@ main() ac_cv_func_gmtime_r=yes rb_cv_large_fd_select=yes ac_cv_type_struct_timeval=yes - ac_cv_func_clock_gettime=yes - ac_cv_func_clock_getres=yes ac_cv_func_malloc_usable_size=no ac_cv_type_off_t=yes ac_cv_sizeof_off_t=8 diff --git a/defs/gmake.mk b/defs/gmake.mk index 5489b017b3fd1a..c3201e25021ad2 100644 --- a/defs/gmake.mk +++ b/defs/gmake.mk @@ -500,7 +500,8 @@ update-deps: # order-only-prerequisites doesn't work for $(RUBYSPEC_CAPIEXT) # because the same named directory exists in the source tree. -$(RUBYSPEC_CAPIEXT)/%.$(DLEXT): $(srcdir)/$(RUBYSPEC_CAPIEXT)/%.c $(srcdir)/$(RUBYSPEC_CAPIEXT)/rubyspec.h $(RUBY_H_INCLUDES) $(LIBRUBY) +$(RUBYSPEC_CAPIEXT)/%.$(DLEXT): $(srcdir)/$(RUBYSPEC_CAPIEXT)/%.c $(RUBYSPEC_CAPIEXT_DEPS) \ + | build-ext $(ECHO) building $@ $(Q) $(MAKEDIRS) $(@D) $(Q) $(DLDSHARED) -L. $(XDLDFLAGS) $(XLDFLAGS) $(LDFLAGS) $(INCFLAGS) $(CPPFLAGS) $(OUTFLAG)$@ $< $(LIBRUBYARG) diff --git a/enc/depend b/enc/depend index 12ddbc223a9afe..cf2ca2d9daa508 100644 --- a/enc/depend +++ b/enc/depend @@ -6972,6 +6972,7 @@ enc/trans/iso2022.$(OBJEXT): internal/attr/nodiscard.h enc/trans/iso2022.$(OBJEXT): internal/attr/noexcept.h enc/trans/iso2022.$(OBJEXT): internal/attr/noinline.h enc/trans/iso2022.$(OBJEXT): internal/attr/nonnull.h +enc/trans/iso2022.$(OBJEXT): internal/attr/nonstring.h enc/trans/iso2022.$(OBJEXT): internal/attr/noreturn.h enc/trans/iso2022.$(OBJEXT): internal/attr/packed_struct.h enc/trans/iso2022.$(OBJEXT): internal/attr/pure.h diff --git a/enc/trans/iso2022.trans b/enc/trans/iso2022.trans index a441f1596dc6ca..ea7d2c8aec90fe 100644 --- a/enc/trans/iso2022.trans +++ b/enc/trans/iso2022.trans @@ -1,4 +1,5 @@ #include "transcode_data.h" +#include "ruby/internal/attr/nonstring.h" <% map = { @@ -443,7 +444,7 @@ rb_cp50221_encoder = { iso2022jp_encoder_reset_sequence_size, finish_iso2022jp_encoder }; -static const char *tbl0208 = +RBIMPL_ATTR_NONSTRING() static const char *tbl0208 = "\x21\x23\x21\x56\x21\x57\x21\x22\x21\x26\x25\x72\x25\x21\x25\x23" \ "\x25\x25\x25\x27\x25\x29\x25\x63\x25\x65\x25\x67\x25\x43\x21\x3C" \ "\x25\x22\x25\x24\x25\x26\x25\x28\x25\x2A\x25\x2B\x25\x2D\x25\x2F" \ diff --git a/error.c b/error.c index 9340bf5673faf0..32409e1e415e39 100644 --- a/error.c +++ b/error.c @@ -1662,7 +1662,7 @@ exc_detailed_message(int argc, VALUE *argv, VALUE exc) VALUE highlight = check_highlight_keyword(opt, 0); - extern VALUE rb_decorate_message(const VALUE eclass, const VALUE emesg, int highlight); + extern VALUE rb_decorate_message(const VALUE eclass, VALUE emesg, int highlight); return rb_decorate_message(CLASS_OF(exc), rb_get_message(exc), RTEST(highlight)); } diff --git a/eval_error.c b/eval_error.c index bdce295f6ec5b3..d58df5a7378529 100644 --- a/eval_error.c +++ b/eval_error.c @@ -125,7 +125,7 @@ print_errinfo(const VALUE eclass, const VALUE errat, const VALUE emesg, const VA } VALUE -rb_decorate_message(const VALUE eclass, const VALUE emesg, int highlight) +rb_decorate_message(const VALUE eclass, VALUE emesg, int highlight) { const char *einfo = ""; long elen = 0; @@ -210,6 +210,8 @@ rb_decorate_message(const VALUE eclass, const VALUE emesg, int highlight) } } + RB_GC_GUARD(emesg); + return str; } diff --git a/ext/date/date_core.c b/ext/date/date_core.c index f4b390584bc793..55706088f4274d 100644 --- a/ext/date/date_core.c +++ b/ext/date/date_core.c @@ -6941,13 +6941,24 @@ d_lite_eql_p(VALUE self, VALUE other) static VALUE d_lite_hash(VALUE self) { - st_index_t v, h[4]; + st_index_t v, h[5]; + VALUE nth; get_d1(self); - h[0] = m_nth(dat); - h[1] = m_jd(dat); - h[2] = m_df(dat); - h[3] = m_sf(dat); + nth = m_nth(dat); + + if (FIXNUM_P(nth)) { + h[0] = 0; + h[1] = (st_index_t)nth; + } else { + h[0] = 1; + h[1] = (st_index_t)FIX2LONG(rb_hash(nth)); + } + + h[2] = m_jd(dat); + h[3] = m_df(dat); + h[4] = m_sf(dat); + v = rb_memhash(h, sizeof(h)); return ST2FIX(v); } diff --git a/ext/etc/extconf.rb b/ext/etc/extconf.rb index 2e28d5803775b5..c4929c02d23c6f 100644 --- a/ext/etc/extconf.rb +++ b/ext/etc/extconf.rb @@ -58,7 +58,7 @@ # TODO: remove when dropping 2.7 support, as exported since 3.0 have_func('rb_deprecate_constant(Qnil, "None")') -have_func("rb_io_descriptor") +have_func("rb_io_descriptor", "ruby/io.h") $distcleanfiles << "constdefs.h" diff --git a/ext/io/console/extconf.rb b/ext/io/console/extconf.rb index aa0b6c6cfbf46e..c9d37a48d78f46 100644 --- a/ext/io/console/extconf.rb +++ b/ext/io/console/extconf.rb @@ -6,11 +6,11 @@ rescue end -have_func("rb_io_path") -have_func("rb_io_descriptor") -have_func("rb_io_get_write_io") -have_func("rb_io_closed_p") -have_func("rb_io_open_descriptor") +have_func("rb_io_path", "ruby/io.h") +have_func("rb_io_descriptor", "ruby/io.h") +have_func("rb_io_get_write_io", "ruby/io.h") +have_func("rb_io_closed_p", "ruby/io.h") +have_func("rb_io_open_descriptor", "ruby/io.h") ok = true if RUBY_ENGINE == "ruby" || RUBY_ENGINE == "truffleruby" hdr = nil diff --git a/ext/io/nonblock/extconf.rb b/ext/io/nonblock/extconf.rb index a1e6075c9b5052..505c9e6252fb99 100644 --- a/ext/io/nonblock/extconf.rb +++ b/ext/io/nonblock/extconf.rb @@ -7,7 +7,7 @@ return end -have_func("rb_io_descriptor") +have_func("rb_io_descriptor", "ruby/io.h") hdr = %w"fcntl.h" if have_macro("O_NONBLOCK", hdr) and diff --git a/ext/io/wait/extconf.rb b/ext/io/wait/extconf.rb index e63c0461873187..ba223f0ac24ad6 100644 --- a/ext/io/wait/extconf.rb +++ b/ext/io/wait/extconf.rb @@ -5,8 +5,8 @@ File.write("Makefile", dummy_makefile($srcdir).join("")) else target = "io/wait" - have_func("rb_io_wait") - have_func("rb_io_descriptor") + have_func("rb_io_wait", "ruby/io.h") + have_func("rb_io_descriptor", "ruby/io.h") unless macro_defined?("DOSISH", "#include ") have_header(ioctl_h = "sys/ioctl.h") or ioctl_h = nil fionread = %w[sys/ioctl.h sys/filio.h sys/socket.h].find do |h| diff --git a/ext/json/parser/extconf.rb b/ext/json/parser/extconf.rb index feb586e1b4d687..4723a02aee06fd 100644 --- a/ext/json/parser/extconf.rb +++ b/ext/json/parser/extconf.rb @@ -1,8 +1,8 @@ # frozen_string_literal: false require 'mkmf' -have_func("rb_enc_raise", "ruby.h") -have_func("rb_enc_interned_str", "ruby.h") +have_func("rb_enc_raise", "ruby/encoding.h") +have_func("rb_enc_interned_str", "ruby/encoding.h") # checking if String#-@ (str_uminus) dedupes... ' begin diff --git a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb index 56f4a1c3ab0ea6..7a768867f8a1a4 100644 --- a/ext/openssl/extconf.rb +++ b/ext/openssl/extconf.rb @@ -47,7 +47,7 @@ $defs.push("-D""OPENSSL_SUPPRESS_DEPRECATED") -have_func("rb_io_descriptor") +have_func("rb_io_descriptor", "ruby/io.h") have_func("rb_io_maybe_wait(0, Qnil, Qnil, Qnil)", "ruby/io.h") # Ruby 3.1 Logging::message "=== Checking for system dependent stuff... ===\n" diff --git a/ext/socket/rubysocket.h b/ext/socket/rubysocket.h index 283735b12ce68c..920e276578ebd4 100644 --- a/ext/socket/rubysocket.h +++ b/ext/socket/rubysocket.h @@ -290,8 +290,8 @@ extern VALUE rb_eResolution; #ifdef SOCKS extern VALUE rb_cSOCKSSocket; # ifndef SOCKS5 -void SOCKSinit(); -int Rconnect(); +void SOCKSinit(char *); +int Rconnect(int, const struct sockaddr *, socklen_t); # endif #endif diff --git a/ext/strscan/extconf.rb b/ext/strscan/extconf.rb index bd65606a4e5984..3c311d2364b7d7 100644 --- a/ext/strscan/extconf.rb +++ b/ext/strscan/extconf.rb @@ -2,8 +2,8 @@ require 'mkmf' if RUBY_ENGINE == 'ruby' $INCFLAGS << " -I$(top_srcdir)" if $extmk - have_func("onig_region_memsize", "ruby.h") - have_func("rb_reg_onig_match", "ruby.h") + have_func("onig_region_memsize(NULL)") + have_func("rb_reg_onig_match", "ruby/re.h") create_makefile 'strscan' else File.write('Makefile', dummy_makefile("").join) diff --git a/gems/bundled_gems b/gems/bundled_gems index 40d79c6a3ccc8d..42a167f7718513 100644 --- a/gems/bundled_gems +++ b/gems/bundled_gems @@ -12,7 +12,7 @@ test-unit 3.6.1 https://github.com/test-unit/test-unit rexml 3.3.9 https://github.com/ruby/rexml rss 0.3.1 https://github.com/ruby/rss net-ftp 0.3.4 https://github.com/ruby/net-ftp -net-imap 0.4.19 https://github.com/ruby/net-imap +net-imap 0.4.21 https://github.com/ruby/net-imap net-pop 0.1.2 https://github.com/ruby/net-pop net-smtp 0.5.1 https://github.com/ruby/net-smtp matrix 0.4.2 https://github.com/ruby/matrix diff --git a/hash.c b/hash.c index 6b1941ebcbee8e..2142132597a994 100644 --- a/hash.c +++ b/hash.c @@ -860,7 +860,7 @@ ar_general_foreach(VALUE hash, st_foreach_check_callback_func *func, st_update_c if (replace) { VALUE key = pair->key; VALUE val = pair->val; - retval = (*replace)(&key, &val, arg, TRUE); + (*replace)(&key, &val, arg, TRUE); // TODO: pair should be same as pair before. ar_table_pair *pair = RHASH_AR_TABLE_REF(hash, i); @@ -931,7 +931,7 @@ ar_foreach_check(VALUE hash, st_foreach_check_callback_func *func, st_data_t arg if (pair->key == never) break; ret = ar_find_entry_hint(hash, hint, key); if (ret == RHASH_AR_TABLE_MAX_BOUND) { - retval = (*func)(0, 0, arg, 1); + (*func)(0, 0, arg, 1); return 2; } } @@ -1391,6 +1391,7 @@ hash_foreach_ensure(VALUE hash) return 0; } +/* This does not manage iteration level */ int rb_hash_stlike_foreach(VALUE hash, st_foreach_callback_func *func, st_data_t arg) { @@ -1402,6 +1403,7 @@ rb_hash_stlike_foreach(VALUE hash, st_foreach_callback_func *func, st_data_t arg } } +/* This does not manage iteration level */ int rb_hash_stlike_foreach_with_replace(VALUE hash, st_foreach_check_callback_func *func, st_update_callback_func *replace, st_data_t arg) { @@ -1708,14 +1710,14 @@ tbl_update(VALUE hash, VALUE key, tbl_update_func func, st_data_t optional_arg) .func = func, .hash = hash, .key = key, - .value = (VALUE)optional_arg, + .value = 0 }; int ret = rb_hash_stlike_update(hash, key, tbl_update_modify, (st_data_t)&arg); /* write barrier */ RB_OBJ_WRITTEN(hash, Qundef, arg.key); - RB_OBJ_WRITTEN(hash, Qundef, arg.value); + if (arg.value) RB_OBJ_WRITTEN(hash, Qundef, arg.value); return ret; } @@ -3326,6 +3328,20 @@ transform_values_foreach_replace(st_data_t *key, st_data_t *value, st_data_t arg return ST_CONTINUE; } +static VALUE +transform_values_call(VALUE hash) +{ + rb_hash_stlike_foreach_with_replace(hash, transform_values_foreach_func, transform_values_foreach_replace, hash); + return hash; +} + +static void +transform_values(VALUE hash) +{ + hash_iter_lev_inc(hash); + rb_ensure(transform_values_call, hash, hash_foreach_ensure, hash); +} + /* * call-seq: * hash.transform_values {|value| ... } -> new_hash @@ -3356,7 +3372,7 @@ rb_hash_transform_values(VALUE hash) SET_DEFAULT(result, Qnil); if (!RHASH_EMPTY_P(hash)) { - rb_hash_stlike_foreach_with_replace(result, transform_values_foreach_func, transform_values_foreach_replace, result); + transform_values(result); compact_after_delete(result); } @@ -3385,7 +3401,7 @@ rb_hash_transform_values_bang(VALUE hash) rb_hash_modify_check(hash); if (!RHASH_TABLE_EMPTY_P(hash)) { - rb_hash_stlike_foreach_with_replace(hash, transform_values_foreach_func, transform_values_foreach_replace, hash); + transform_values(hash); } return hash; @@ -3896,30 +3912,70 @@ rb_hash_update_i(VALUE key, VALUE value, VALUE hash) return ST_CONTINUE; } +struct update_call_args { + VALUE hash, newvalue, *argv; + int argc; + bool block_given; + bool iterating; +}; + static int rb_hash_update_block_callback(st_data_t *key, st_data_t *value, struct update_arg *arg, int existing) { - st_data_t newvalue = arg->arg; + VALUE k = (VALUE)*key, v = (VALUE)*value; + struct update_call_args *ua = (void *)arg->arg; + VALUE newvalue = ua->newvalue, hash = arg->hash; if (existing) { - newvalue = (st_data_t)rb_yield_values(3, (VALUE)*key, (VALUE)*value, (VALUE)newvalue); + hash_iter_lev_inc(hash); + ua->iterating = true; + newvalue = rb_yield_values(3, k, v, newvalue); + hash_iter_lev_dec(hash); + ua->iterating = false; } - else if (RHASH_STRING_KEY_P(arg->hash, *key) && !RB_OBJ_FROZEN(*key)) { - *key = rb_hash_key_str(*key); + else if (RHASH_STRING_KEY_P(hash, k) && !RB_OBJ_FROZEN(k)) { + *key = (st_data_t)rb_hash_key_str(k); } - *value = newvalue; + *value = (st_data_t)newvalue; return ST_CONTINUE; } NOINSERT_UPDATE_CALLBACK(rb_hash_update_block_callback) static int -rb_hash_update_block_i(VALUE key, VALUE value, VALUE hash) +rb_hash_update_block_i(VALUE key, VALUE value, VALUE args) { - RHASH_UPDATE(hash, key, rb_hash_update_block_callback, value); + struct update_call_args *ua = (void *)args; + ua->newvalue = value; + RHASH_UPDATE(ua->hash, key, rb_hash_update_block_callback, args); return ST_CONTINUE; } +static VALUE +rb_hash_update_call(VALUE args) +{ + struct update_call_args *arg = (void *)args; + + for (int i = 0; i < arg->argc; i++){ + VALUE hash = to_hash(arg->argv[i]); + if (arg->block_given) { + rb_hash_foreach(hash, rb_hash_update_block_i, args); + } + else { + rb_hash_foreach(hash, rb_hash_update_i, arg->hash); + } + } + return arg->hash; +} + +static VALUE +rb_hash_update_ensure(VALUE args) +{ + struct update_call_args *ua = (void *)args; + if (ua->iterating) hash_iter_lev_dec(ua->hash); + return Qnil; +} + /* * call-seq: * hash.merge! -> self @@ -3971,20 +4027,17 @@ rb_hash_update_block_i(VALUE key, VALUE value, VALUE hash) static VALUE rb_hash_update(int argc, VALUE *argv, VALUE self) { - int i; - bool block_given = rb_block_given_p(); + struct update_call_args args = { + .hash = self, + .argv = argv, + .argc = argc, + .block_given = rb_block_given_p(), + .iterating = false, + }; + VALUE arg = (VALUE)&args; rb_hash_modify(self); - for (i = 0; i < argc; i++){ - VALUE hash = to_hash(argv[i]); - if (block_given) { - rb_hash_foreach(hash, rb_hash_update_block_i, self); - } - else { - rb_hash_foreach(hash, rb_hash_update_i, self); - } - } - return self; + return rb_ensure(rb_hash_update_call, arg, rb_hash_update_ensure, arg); } struct update_func_arg { diff --git a/include/ruby/internal/anyargs.h b/include/ruby/internal/anyargs.h index e3e1b6166db3fa..e4c6d155cc7b26 100644 --- a/include/ruby/internal/anyargs.h +++ b/include/ruby/internal/anyargs.h @@ -84,12 +84,15 @@ #elif defined(_WIN32) || defined(__CYGWIN__) # /* Skip due to [Bug #16134] */ +# define RBIMPL_CAST_FN_PTR 1 #elif ! RBIMPL_HAS_ATTRIBUTE(transparent_union) # /* :TODO: improve here, please find a way to support. */ +# define RBIMPL_CAST_FN_PTR 1 #elif ! defined(HAVE_VA_ARGS_MACRO) # /* :TODO: improve here, please find a way to support. */ +# define RBIMPL_CAST_FN_PTR 1 #else # /** @cond INTERNAL_MACRO */ @@ -348,6 +351,25 @@ RBIMPL_ANYARGS_DECL(rb_define_method, VALUE, const char *) #endif /* __cplusplus */ +#if defined(RBIMPL_CAST_FN_PTR) && !defined(__cplusplus) +/* In C23, K&R style prototypes are gone and so `void foo(ANYARGS)` became + * equivalent to `void foo(void)` unlike in earlier versions. This is a problem + * for rb_define_* functions since that makes all valid functions one can pass + * trip -Wincompatible-pointer-types, which we treat as errors. This is mostly + * not a problem for the __builtin_choose_expr path, but outside of that we + * need to add a cast for compatibility. + */ +#define rb_define_method(klass, mid, func, arity) rb_define_method((klass), (mid), (VALUE (*)(ANYARGS))(func), (arity)) +#define rb_define_method_id(klass, mid, func, arity) rb_define_method_id((klass), (mid), (VALUE (*)(ANYARGS))(func), (arity)) +#define rb_define_singleton_method(obj, mid, func, arity) rb_define_singleton_method((obj), (mid), (VALUE (*)(ANYARGS))(func), (arity)) +#define rb_define_protected_method(klass, mid, func, arity) rb_define_protected_method((klass), (mid), (VALUE (*)(ANYARGS))(func), (arity)) +#define rb_define_private_method(klass, mid, func, arity) rb_define_private_method((klass), (mid), (VALUE (*)(ANYARGS))(func), (arity)) +#define rb_define_module_function(mod, mid, func, arity) rb_define_module_function((mod), (mid), (VALUE (*)(ANYARGS))(func), (arity)) +#define rb_define_global_function(mid, func, arity) rb_define_global_function((mid), (VALUE (*)(ANYARGS))(func), (arity)) + +#undef RBIMPL_CAST_FN_PTR +#endif /* defined(RBIMPL_CAST_FN_PTR) && !defined(__cplusplus) */ + /** * This macro is to properly cast a function parameter of *_define_method * family. It has been around since 1.x era so you can maximise backwards diff --git a/include/ruby/internal/attr/nonstring.h b/include/ruby/internal/attr/nonstring.h new file mode 100644 index 00000000000000..de26e926d4e7ad --- /dev/null +++ b/include/ruby/internal/attr/nonstring.h @@ -0,0 +1,32 @@ +#ifndef RBIMPL_ATTR_NONSTRING_H /*-*-C++-*-vi:se ft=cpp:*/ +#define RBIMPL_ATTR_NONSTRING_H +/** + * @file + * @author Ruby developers + * @copyright This file is a part of the programming language Ruby. + * Permission is hereby granted, to either redistribute and/or + * modify this file, provided that the conditions mentioned in the + * file COPYING are met. Consult the file for details. + * @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are + * implementation details. Don't take them as canon. They could + * rapidly appear then vanish. The name (path) of this header file + * is also an implementation detail. Do not expect it to persist + * at the place it is now. Developers are free to move it anywhere + * anytime at will. + * @note To ruby-core: remember that this header can be possibly + * recursively included from extension libraries written in C++. + * Do not expect for instance `__VA_ARGS__` is always available. + * We assume C99 for ruby itself but we don't assume languages of + * extension libraries. They could be written in C++98. + * @brief Defines #RBIMPL_ATTR_NONSTRING. + */ +#include "ruby/internal/has/attribute.h" + +/** Wraps (or simulates) `__attribute__((nonstring))` */ +#if RBIMPL_HAS_ATTRIBUTE(nonstring) +# define RBIMPL_ATTR_NONSTRING() __attribute__((nonstring)) +#else +# define RBIMPL_ATTR_NONSTRING() /* void */ +#endif + +#endif /* RBIMPL_ATTR_NONSTRING_H */ diff --git a/include/ruby/internal/stdbool.h b/include/ruby/internal/stdbool.h index 1ca61136ba2636..cfe73437a2549b 100644 --- a/include/ruby/internal/stdbool.h +++ b/include/ruby/internal/stdbool.h @@ -35,17 +35,9 @@ # define __bool_true_false_are_defined # endif -#elif defined(HAVE_STDBOOL_H) -# /* Take stdbool.h definition. */ +#else +# /* Take stdbool.h definition. It exists since GCC 3.0 and VS 2015. */ # include - -#elif !defined(HAVE__BOOL) -typedef unsigned char _Bool; -# /* See also http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2229.htm */ -# define bool _Bool -# define true ((_Bool)+1) -# define false ((_Bool)+0) -# define __bool_true_false_are_defined #endif #endif /* RBIMPL_STDBOOL_H */ diff --git a/include/ruby/win32.h b/include/ruby/win32.h index dfb56f418237bc..cfa31db130f448 100644 --- a/include/ruby/win32.h +++ b/include/ruby/win32.h @@ -125,8 +125,15 @@ typedef unsigned int uintptr_t; #define O_SHARE_DELETE 0x20000000 /* for rb_w32_open(), rb_w32_wopen() */ typedef int clockid_t; +#if defined(__MINGW32__) +#undef CLOCK_PROCESS_CPUTIME_ID +#undef CLOCK_THREAD_CPUTIME_ID +#undef CLOCK_REALTIME_COARSE +#endif +#if defined(HAVE_CLOCK_GETTIME) && !defined(CLOCK_REALTIME) #define CLOCK_REALTIME 0 #define CLOCK_MONOTONIC 1 +#endif #undef utime #undef lseek diff --git a/iseq.c b/iseq.c index 3bdb1c0af50e05..d28d68206b7ec1 100644 --- a/iseq.c +++ b/iseq.c @@ -3484,7 +3484,7 @@ rb_vm_encoded_insn_data_table_init(void) const void * const *table = rb_vm_get_insns_address_table(); #define INSN_CODE(insn) ((VALUE)table[insn]) #else -#define INSN_CODE(insn) (insn) +#define INSN_CODE(insn) ((VALUE)(insn)) #endif st_data_t insn; encoded_insn_data = st_init_numtable_with_size(VM_INSTRUCTION_SIZE / 2); diff --git a/lib/mkmf.rb b/lib/mkmf.rb index 6da7dde5f1d9b3..51585b135c238c 100644 --- a/lib/mkmf.rb +++ b/lib/mkmf.rb @@ -2465,7 +2465,7 @@ def create_makefile(target, srcprefix = nil) dest = "#{dir}/#{File.basename(f)}" mfile.print("do-install-rb#{sfx}: #{dest}\n") mfile.print("#{dest}: #{f} #{timestamp_file(dir, target_prefix)}\n") - mfile.print("\t$(Q) $(#{$extout ? 'COPY' : 'INSTALL_DATA'}) #{f} $(@D)\n") + mfile.print("\t$(Q) $(#{$extout ? 'COPY' : 'INSTALL_DATA'}) #{f} $@\n") if defined?($installed_list) and !$extout mfile.print("\t@echo #{dest}>>$(INSTALLED_LIST)\n") end diff --git a/lib/resolv.rb b/lib/resolv.rb index 57fd17375035c6..0f08a0c456ae51 100644 --- a/lib/resolv.rb +++ b/lib/resolv.rb @@ -37,7 +37,7 @@ class Resolv - VERSION = "0.3.0" + VERSION = "0.3.1" ## # Looks up the first IP address for +name+. @@ -1655,6 +1655,7 @@ def get_labels prev_index = @index save_index = nil d = [] + size = -1 while true raise DecodeError.new("limit exceeded") if @limit <= @index case @data.getbyte(@index) @@ -1675,7 +1676,10 @@ def get_labels end @index = idx else - d << self.get_label + l = self.get_label + d << l + size += 1 + l.string.bytesize + raise DecodeError.new("name label data exceed 255 octets") if size > 255 end end end diff --git a/marshal.c b/marshal.c index 6cb636f3ff78b3..3ef3ef36366688 100644 --- a/marshal.c +++ b/marshal.c @@ -40,6 +40,7 @@ #include "ruby/util.h" #include "builtin.h" #include "shape.h" +#include "ruby/internal/attr/nonstring.h" #define BITSPERSHORT (2*CHAR_BIT) #define SHORTMASK ((1<symbols, orig_sym, arg->symbols->num_entries); - if (!NIL_P(encname)) { - struct dump_call_arg c_arg; - c_arg.limit = 1; - c_arg.arg = arg; - w_long(1L, arg); - w_encoding(encname, &c_arg); - } + w_encname(encname, arg); } } @@ -964,19 +977,23 @@ w_object(VALUE obj, struct dump_arg *arg, int limit) if (FL_TEST(obj, FL_SINGLETON)) { rb_raise(rb_eTypeError, "singleton class can't be dumped"); } - w_byte(TYPE_CLASS, arg); { VALUE path = class2path(obj); + VALUE encname = w_encivar(path, arg); + w_byte(TYPE_CLASS, arg); w_bytes(RSTRING_PTR(path), RSTRING_LEN(path), arg); + w_encname(encname, arg); RB_GC_GUARD(path); } break; case T_MODULE: - w_byte(TYPE_MODULE, arg); { VALUE path = class2path(obj); + VALUE encname = w_encivar(path, arg); + w_byte(TYPE_MODULE, arg); w_bytes(RSTRING_PTR(path), RSTRING_LEN(path), arg); + w_encname(encname, arg); RB_GC_GUARD(path); } break; @@ -1525,7 +1542,7 @@ name_equal(const char *name, size_t nlen, const char *p, long l) static int sym2encidx(VALUE sym, VALUE val) { - static const char name_encoding[8] = "encoding"; + RBIMPL_ATTR_NONSTRING() static const char name_encoding[8] = "encoding"; const char *p; long l; if (rb_enc_get_index(sym) != ENCINDEX_US_ASCII) return -1; @@ -1713,6 +1730,34 @@ r_copy_ivar(VALUE v, VALUE data) return v; } +static int +r_ivar_encoding(VALUE obj, struct load_arg *arg, VALUE sym, VALUE val) +{ + int idx = sym2encidx(sym, val); + if (idx >= 0) { + if (rb_enc_capable(obj)) { + rb_enc_associate_index(obj, idx); + } + else { + rb_raise(rb_eArgError, "%"PRIsVALUE" is not enc_capable", obj); + } + return TRUE; + } + return FALSE; +} + +static long +r_encname(VALUE obj, struct load_arg *arg) +{ + long len = r_long(arg); + if (len > 0) { + VALUE sym = r_symbol(arg); + VALUE val = r_object(arg); + len -= r_ivar_encoding(obj, arg, sym, val); + } + return len; +} + static void r_ivar(VALUE obj, int *has_encoding, struct load_arg *arg) { @@ -1723,14 +1768,7 @@ r_ivar(VALUE obj, int *has_encoding, struct load_arg *arg) do { VALUE sym = r_symbol(arg); VALUE val = r_object(arg); - int idx = sym2encidx(sym, val); - if (idx >= 0) { - if (rb_enc_capable(obj)) { - rb_enc_associate_index(obj, idx); - } - else { - rb_raise(rb_eArgError, "%"PRIsVALUE" is not enc_capable", obj); - } + if (r_ivar_encoding(obj, arg, sym, val)) { if (has_encoding) *has_encoding = TRUE; } else if (symname_equal_lit(sym, name_s_ruby2_keywords_flag)) { @@ -2256,6 +2294,7 @@ r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE extmod, int typ { VALUE str = r_bytes(arg); + if (ivp && *ivp > 0) *ivp = r_encname(str, arg) > 0; v = path2class(str); prohibit_ivar("class", str); v = r_entry(v, arg); @@ -2267,6 +2306,7 @@ r_object_for(struct load_arg *arg, bool partial, int *ivp, VALUE extmod, int typ { VALUE str = r_bytes(arg); + if (ivp && *ivp > 0) *ivp = r_encname(str, arg) > 0; v = path2module(str); prohibit_ivar("module", str); v = r_entry(v, arg); diff --git a/prism_compile.c b/prism_compile.c index b60ca0ac680801..15b5f1cb41deac 100644 --- a/prism_compile.c +++ b/prism_compile.c @@ -2786,7 +2786,7 @@ pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, int event = RUBY_EVENT_LINE; ISEQ_COMPILE_DATA(iseq)->last_line = lineno; - if (ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq)) { + if (lineno > 0 && ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq)) { event |= RUBY_EVENT_COVERAGE_LINE; } ADD_TRACE(ret, event); diff --git a/proc.c b/proc.c index a3fdb1783ce755..f09f5ec4d86a41 100644 --- a/proc.c +++ b/proc.c @@ -22,6 +22,7 @@ #include "method.h" #include "iseq.h" #include "vm_core.h" +#include "ractor_core.h" #include "yjit.h" const rb_cref_t *rb_vm_cref_in_context(VALUE self, VALUE cbase); @@ -1508,23 +1509,26 @@ rb_sym_to_proc(VALUE sym) long index; ID id; - if (!sym_proc_cache) { - sym_proc_cache = rb_ary_hidden_new(SYM_PROC_CACHE_SIZE * 2); - rb_gc_register_mark_object(sym_proc_cache); - rb_ary_store(sym_proc_cache, SYM_PROC_CACHE_SIZE*2 - 1, Qnil); - } - id = SYM2ID(sym); - index = (id % SYM_PROC_CACHE_SIZE) << 1; - if (RARRAY_AREF(sym_proc_cache, index) == sym) { - return RARRAY_AREF(sym_proc_cache, index + 1); - } - else { - proc = sym_proc_new(rb_cProc, ID2SYM(id)); - RARRAY_ASET(sym_proc_cache, index, sym); - RARRAY_ASET(sym_proc_cache, index + 1, proc); - return proc; + if (rb_ractor_main_p()) { + index = (id % SYM_PROC_CACHE_SIZE) << 1; + if (!sym_proc_cache) { + sym_proc_cache = rb_ary_hidden_new(SYM_PROC_CACHE_SIZE * 2); + rb_gc_register_mark_object(sym_proc_cache); + rb_ary_store(sym_proc_cache, SYM_PROC_CACHE_SIZE*2 - 1, Qnil); + } + if (RARRAY_AREF(sym_proc_cache, index) == sym) { + return RARRAY_AREF(sym_proc_cache, index + 1); + } + else { + proc = sym_proc_new(rb_cProc, ID2SYM(id)); + RARRAY_ASET(sym_proc_cache, index, sym); + RARRAY_ASET(sym_proc_cache, index + 1, proc); + return proc; + } + } else { + return sym_proc_new(rb_cProc, ID2SYM(id)); } } diff --git a/random.c b/random.c index 5cd2d917a4d584..0902114a285ce2 100644 --- a/random.c +++ b/random.c @@ -437,23 +437,17 @@ random_init(int argc, VALUE *argv, VALUE obj) # define USE_DEV_URANDOM 0 #endif -#ifdef HAVE_GETENTROPY -# define MAX_SEED_LEN_PER_READ 256 -static int -fill_random_bytes_urandom(void *seed, size_t size) -{ - unsigned char *p = (unsigned char *)seed; - while (size) { - size_t len = size < MAX_SEED_LEN_PER_READ ? size : MAX_SEED_LEN_PER_READ; - if (getentropy(p, len) != 0) { - return -1; - } - p += len; - size -= len; - } - return 0; -} -#elif USE_DEV_URANDOM +#if ! defined HAVE_GETRANDOM && defined __linux__ && defined __NR_getrandom +# ifndef GRND_NONBLOCK +# define GRND_NONBLOCK 0x0001 /* not defined in musl libc */ +# endif +# define getrandom(ptr, size, flags) \ + (ssize_t)syscall(__NR_getrandom, (ptr), (size), (flags)) +# define HAVE_GETRANDOM 1 +#endif + +/* fill random bytes by reading random device directly */ +#if USE_DEV_URANDOM static int fill_random_bytes_urandom(void *seed, size_t size) { @@ -493,15 +487,7 @@ fill_random_bytes_urandom(void *seed, size_t size) # define fill_random_bytes_urandom(seed, size) -1 #endif -#if ! defined HAVE_GETRANDOM && defined __linux__ && defined __NR_getrandom -# ifndef GRND_NONBLOCK -# define GRND_NONBLOCK 0x0001 /* not defined in musl libc */ -# endif -# define getrandom(ptr, size, flags) \ - (ssize_t)syscall(__NR_getrandom, (ptr), (size), (flags)) -# define HAVE_GETRANDOM 1 -#endif - +/* fill random bytes by library */ #if 0 #elif defined MAC_OS_X_VERSION_10_7 && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_7 @@ -519,7 +505,7 @@ fill_random_bytes_urandom(void *seed, size_t size) # endif static int -fill_random_bytes_syscall(void *seed, size_t size, int unused) +fill_random_bytes_lib(void *seed, size_t size) { #if USE_COMMON_RANDOM CCRNGStatus status = CCRandomGenerateBytes(seed, size); @@ -546,18 +532,16 @@ fill_random_bytes_syscall(void *seed, size_t size, int unused) } return 0; } -#elif defined(HAVE_ARC4RANDOM_BUF) +#elif defined(HAVE_ARC4RANDOM_BUF) && \ + ((defined(__OpenBSD__) && OpenBSD >= 201411) || \ + (defined(__NetBSD__) && __NetBSD_Version__ >= 700000000) || \ + (defined(__FreeBSD__) && __FreeBSD_version >= 1200079)) +// [Bug #15039] arc4random_buf(3) should used only if we know it is fork-safe static int -fill_random_bytes_syscall(void *buf, size_t size, int unused) +fill_random_bytes_lib(void *buf, size_t size) { -#if (defined(__OpenBSD__) && OpenBSD >= 201411) || \ - (defined(__NetBSD__) && __NetBSD_Version__ >= 700000000) || \ - (defined(__FreeBSD__) && __FreeBSD_version >= 1200079) arc4random_buf(buf, size); return 0; -#else - return -1; -#endif } #elif defined(_WIN32) @@ -633,11 +617,17 @@ fill_random_bytes_bcrypt(void *seed, size_t size) } static int -fill_random_bytes_syscall(void *seed, size_t size, int unused) +fill_random_bytes_lib(void *seed, size_t size) { if (fill_random_bytes_bcrypt(seed, size) == 0) return 0; return fill_random_bytes_crypt(seed, size); } +#else +# define fill_random_bytes_lib(seed, size) -1 +#endif + +/* fill random bytes by dedicated syscall */ +#if 0 #elif defined HAVE_GETRANDOM static int fill_random_bytes_syscall(void *seed, size_t size, int need_secure) @@ -661,6 +651,31 @@ fill_random_bytes_syscall(void *seed, size_t size, int need_secure) } return -1; } +#elif defined(HAVE_GETENTROPY) +/* + * The Open Group Base Specifications Issue 8 - IEEE Std 1003.1-2024 + * https://pubs.opengroup.org/onlinepubs/9799919799/functions/getentropy.html + * + * NOTE: `getentropy`(3) on Linux is implemented using `getrandom`(2), + * prefer the latter over this if both are defined. + */ +#ifndef GETENTROPY_MAX +# define GETENTROPY_MAX 256 +#endif +static int +fill_random_bytes_syscall(void *seed, size_t size, int need_secure) +{ + unsigned char *p = (unsigned char *)seed; + while (size) { + size_t len = size < GETENTROPY_MAX ? size : GETENTROPY_MAX; + if (getentropy(p, len) != 0) { + return -1; + } + p += len; + size -= len; + } + return 0; +} #else # define fill_random_bytes_syscall(seed, size, need_secure) -1 #endif @@ -670,6 +685,7 @@ ruby_fill_random_bytes(void *seed, size_t size, int need_secure) { int ret = fill_random_bytes_syscall(seed, size, need_secure); if (ret == 0) return ret; + if (fill_random_bytes_lib(seed, size) == 0) return 0; return fill_random_bytes_urandom(seed, size); } diff --git a/regenc.h b/regenc.h index 352a8d79800873..4b4d21a715b4af 100644 --- a/regenc.h +++ b/regenc.h @@ -118,6 +118,11 @@ typedef struct { typedef struct { short int len; +#if defined(__has_attribute) +# if __has_attribute(nonstring) + __attribute__((nonstring)) +# endif +#endif const UChar name[6]; int ctype; } PosixBracketEntryType; diff --git a/signal.c b/signal.c index bef3b2e5375232..589ee05cbd0c40 100644 --- a/signal.c +++ b/signal.c @@ -45,6 +45,7 @@ #include "ruby_atomic.h" #include "vm_core.h" #include "ractor_core.h" +#include "ruby/internal/attr/nonstring.h" #ifdef NEED_RUBY_ATOMIC_OPS rb_atomic_t @@ -968,7 +969,7 @@ check_reserved_signal_(const char *name, size_t name_len, int signo) if (prev) { ssize_t RB_UNUSED_VAR(err); static const int stderr_fd = 2; -#define NOZ(name, str) name[sizeof(str)-1] = str +#define NOZ(name, str) RBIMPL_ATTR_NONSTRING() name[sizeof(str)-1] = str static const char NOZ(msg1, " received in "); static const char NOZ(msg2, " handler\n"); diff --git a/siphash.c b/siphash.c index 61b8604fc9df8c..62de6227786160 100644 --- a/siphash.c +++ b/siphash.c @@ -140,6 +140,9 @@ xor64_to(uint64_t *v, const uint64_t s) #endif static const union { +#if defined(__has_attribute) && __has_attribute(nonstring) + __attribute__((nonstring)) +#endif char bin[32]; uint64_t u64[4]; } sip_init_state_bin = {"uespemos""modnarod""arenegyl""setybdet"}; diff --git a/spec/bundler/support/builders.rb b/spec/bundler/support/builders.rb index 4d713d870829b5..a0a9d348ab4e2b 100644 --- a/spec/bundler/support/builders.rb +++ b/spec/bundler/support/builders.rb @@ -22,10 +22,6 @@ def pl(platform) Gem::Platform.new(platform) end - def rake_version - "13.2.1" - end - def build_repo1 build_repo gem_repo1 do FileUtils.cp rake_path, "#{gem_repo1}/gems/" diff --git a/spec/bundler/support/path.rb b/spec/bundler/support/path.rb index b26e77d376399d..5807624ba91e2d 100644 --- a/spec/bundler/support/path.rb +++ b/spec/bundler/support/path.rb @@ -280,6 +280,10 @@ def rake_path Dir["#{base_system_gems}/#{Bundler.ruby_scope}/**/rake*.gem"].first end + def rake_version + File.basename(rake_path).delete_prefix("rake-").delete_suffix(".gem") + end + private def git_ls_files(glob) diff --git a/spec/ruby/core/file/atime_spec.rb b/spec/ruby/core/file/atime_spec.rb index 1b47576e6b996f..e47e70e5acf35b 100644 --- a/spec/ruby/core/file/atime_spec.rb +++ b/spec/ruby/core/file/atime_spec.rb @@ -27,6 +27,9 @@ else File.atime(__FILE__).usec.should == 0 end + rescue Errno::ENOENT => e + # Native Windows don't have stat command. + skip e.message end end end diff --git a/spec/ruby/core/file/ctime_spec.rb b/spec/ruby/core/file/ctime_spec.rb index d17ba1a77f29a0..718f26d5cc9f8d 100644 --- a/spec/ruby/core/file/ctime_spec.rb +++ b/spec/ruby/core/file/ctime_spec.rb @@ -22,6 +22,9 @@ else File.ctime(__FILE__).usec.should == 0 end + rescue Errno::ENOENT => e + # Windows don't have stat command. + skip e.message end end diff --git a/spec/ruby/core/file/mtime_spec.rb b/spec/ruby/core/file/mtime_spec.rb index 5304bbf057bb1d..0e9c95caee310a 100644 --- a/spec/ruby/core/file/mtime_spec.rb +++ b/spec/ruby/core/file/mtime_spec.rb @@ -26,6 +26,9 @@ else File.mtime(__FILE__).usec.should == 0 end + rescue Errno::ENOENT => e + # Windows don't have stat command. + skip e.message end end end diff --git a/spec/ruby/core/kernel/shared/require.rb b/spec/ruby/core/kernel/shared/require.rb index 250813191b8ead..b31c89e3bf346a 100644 --- a/spec/ruby/core/kernel/shared/require.rb +++ b/spec/ruby/core/kernel/shared/require.rb @@ -223,7 +223,7 @@ it "loads c-extension file when passed absolute path without extension when no .rb is present" do # the error message is specific to what dlerror() returns path = File.join CODE_LOADING_DIR, "a", "load_fixture" - -> { @object.send(@method, path) }.should raise_error(Exception, /file too short|not a mach-o file/) + -> { @object.send(@method, path) }.should raise_error(LoadError) end end @@ -231,7 +231,7 @@ it "loads .bundle file when passed absolute path with .so" do # the error message is specific to what dlerror() returns path = File.join CODE_LOADING_DIR, "a", "load_fixture.so" - -> { @object.send(@method, path) }.should raise_error(Exception, /load_fixture\.bundle.+(file too short|not a mach-o file)/) + -> { @object.send(@method, path) }.should raise_error(LoadError) end end diff --git a/spec/ruby/core/marshal/dump_spec.rb b/spec/ruby/core/marshal/dump_spec.rb index eaf238bbd93a85..cb34fa2f0376e7 100644 --- a/spec/ruby/core/marshal/dump_spec.rb +++ b/spec/ruby/core/marshal/dump_spec.rb @@ -193,9 +193,12 @@ def _dump(level) Marshal.dump(MarshalSpec::ClassWithOverriddenName).should == "\x04\bc)MarshalSpec::ClassWithOverriddenName" end - it "dumps a class with multibyte characters in name" do - source_object = eval("MarshalSpec::MultibyteぁあぃいClass".force_encoding(Encoding::UTF_8)) - Marshal.dump(source_object).should == "\x04\bc,MarshalSpec::Multibyte\xE3\x81\x81\xE3\x81\x82\xE3\x81\x83\xE3\x81\x84Class" + ruby_version_is "3.3" do + it "dumps a class with multibyte characters in name" do + source_object = eval("MarshalSpec::MultibyteぁあぃいClass".dup.force_encoding(Encoding::UTF_8)) + Marshal.dump(source_object).should == "\x04\bIc,MarshalSpec::Multibyte\xE3\x81\x81\xE3\x81\x82\xE3\x81\x83\xE3\x81\x84Class\x06:\x06ET" + Marshal.load(Marshal.dump(source_object)) == source_object + end end it "raises TypeError with an anonymous Class" do @@ -216,9 +219,12 @@ def _dump(level) Marshal.dump(MarshalSpec::ModuleWithOverriddenName).should == "\x04\bc*MarshalSpec::ModuleWithOverriddenName" end - it "dumps a module with multibyte characters in name" do - source_object = eval("MarshalSpec::MultibyteけげこごModule".force_encoding(Encoding::UTF_8)) - Marshal.dump(source_object).should == "\x04\bm-MarshalSpec::Multibyte\xE3\x81\x91\xE3\x81\x92\xE3\x81\x93\xE3\x81\x94Module" + ruby_version_is "3.3" do + it "dumps a module with multibyte characters in name" do + source_object = eval("MarshalSpec::MultibyteけげこごModule".dup.force_encoding(Encoding::UTF_8)) + Marshal.dump(source_object).should == "\x04\bIm-MarshalSpec::Multibyte\xE3\x81\x91\xE3\x81\x92\xE3\x81\x93\xE3\x81\x94Module\x06:\x06ET" + Marshal.load(Marshal.dump(source_object)) == source_object + end end it "raises TypeError with an anonymous Module" do @@ -684,9 +690,12 @@ def finalizer.noop(_) Marshal.dump(obj).should include("MarshalSpec::TimeWithOverriddenName") end - it "dumps a Time subclass with multibyte characters in name" do - source_object = eval("MarshalSpec::MultibyteぁあぃいTime".force_encoding(Encoding::UTF_8)) - Marshal.dump(source_object).should == "\x04\bc+MarshalSpec::Multibyte\xE3\x81\x81\xE3\x81\x82\xE3\x81\x83\xE3\x81\x84Time" + ruby_version_is "3.3" do + it "dumps a Time subclass with multibyte characters in name" do + source_object = eval("MarshalSpec::MultibyteぁあぃいTime".dup.force_encoding(Encoding::UTF_8)) + Marshal.dump(source_object).should == "\x04\bIc+MarshalSpec::Multibyte\xE3\x81\x81\xE3\x81\x82\xE3\x81\x83\xE3\x81\x84Time\x06:\x06ET" + Marshal.load(Marshal.dump(source_object)) == source_object + end end it "raises TypeError with an anonymous Time subclass" do diff --git a/st.c b/st.c index 50bfd4bfbb4e42..ab361e1ca8f33a 100644 --- a/st.c +++ b/st.c @@ -1482,7 +1482,16 @@ st_update(st_table *tab, st_data_t key, value = entry->record; } old_key = key; + + unsigned int rebuilds_num = tab->rebuilds_num; + retval = (*func)(&key, &value, arg, existing); + + // We need to make sure that the callback didn't cause a table rebuild + // Ideally we would make sure no operations happened + assert(rebuilds_num == tab->rebuilds_num); + (void)rebuilds_num; + switch (retval) { case ST_CONTINUE: if (! existing) { diff --git a/string.c b/string.c index 7c3a790fa3b78d..41cdfe0c65f484 100644 --- a/string.c +++ b/string.c @@ -44,6 +44,7 @@ #include "ruby/util.h" #include "ruby_assert.h" #include "vm_sync.h" +#include "ruby/internal/attr/nonstring.h" #if defined HAVE_CRYPT_R # if defined HAVE_CRYPT_H @@ -8813,11 +8814,15 @@ rb_str_split_m(int argc, VALUE *argv, VALUE str) } } -#define SPLIT_STR(beg, len) (empty_count = split_string(result, str, beg, len, empty_count)) +#define SPLIT_STR(beg, len) ( \ + empty_count = split_string(result, str, beg, len, empty_count), \ + str_mod_check(str, str_start, str_len)) beg = 0; char *ptr = RSTRING_PTR(str); - char *eptr = RSTRING_END(str); + char *const str_start = ptr; + const long str_len = RSTRING_LEN(str); + char *const eptr = str_start + str_len; if (split_type == SPLIT_TYPE_AWK) { char *bptr = ptr; int skip = 1; @@ -8878,7 +8883,6 @@ rb_str_split_m(int argc, VALUE *argv, VALUE str) } } else if (split_type == SPLIT_TYPE_STRING) { - char *str_start = ptr; char *substr_start = ptr; char *sptr = RSTRING_PTR(spat); long slen = RSTRING_LEN(spat); @@ -8895,6 +8899,7 @@ rb_str_split_m(int argc, VALUE *argv, VALUE str) continue; } SPLIT_STR(substr_start - str_start, (ptr+end) - substr_start); + str_mod_check(spat, sptr, slen); ptr += end + slen; substr_start = ptr; if (!NIL_P(limit) && lim <= ++i) break; @@ -8902,7 +8907,6 @@ rb_str_split_m(int argc, VALUE *argv, VALUE str) beg = ptr - str_start; } else if (split_type == SPLIT_TYPE_CHARS) { - char *str_start = ptr; int n; if (result) result = rb_ary_new_capa(RSTRING_LEN(str)); @@ -11120,7 +11124,7 @@ enc_str_scrub(rb_encoding *enc, VALUE str, VALUE repl, int cr) encidx = rb_enc_to_index(enc); #define DEFAULT_REPLACE_CHAR(str) do { \ - static const char replace[sizeof(str)-1] = str; \ + RBIMPL_ATTR_NONSTRING() static const char replace[sizeof(str)-1] = str; \ rep = replace; replen = (int)sizeof(replace); \ } while (0) diff --git a/struct.c b/struct.c index c54dc12a04df04..23420d5e8cc628 100644 --- a/struct.c +++ b/struct.c @@ -52,7 +52,8 @@ struct_ivar_get(VALUE c, ID id) RUBY_ASSERT(RB_TYPE_P(c, T_CLASS)); ivar = rb_attr_get(c, id); if (!NIL_P(ivar)) { - return rb_ivar_set(orig, id, ivar); + if (!OBJ_FROZEN(orig)) rb_ivar_set(orig, id, ivar); + return ivar; } } } diff --git a/symbol.c b/symbol.c index bdbfbae831295a..325afccfe0faab 100644 --- a/symbol.c +++ b/symbol.c @@ -22,6 +22,7 @@ #include "symbol.h" #include "vm_sync.h" #include "builtin.h" +#include "ruby/internal/attr/nonstring.h" #if defined(USE_SYMBOL_GC) && !(USE_SYMBOL_GC+0) # undef USE_SYMBOL_GC diff --git a/template/Makefile.in b/template/Makefile.in index 8c462f20fb42e5..a071d8dbd2ed5e 100644 --- a/template/Makefile.in +++ b/template/Makefile.in @@ -74,7 +74,8 @@ DOCTARGETS = @RDOCTARGET@ @CAPITARGET@ EXTOUT = @EXTOUT@ TIMESTAMPDIR = $(EXTOUT)/.timestamp -arch_hdrdir = $(EXTOUT)/include/$(arch) +ext_hdrdir = $(EXTOUT)/include +arch_hdrdir = $(ext_hdrdir)/$(arch) VPATH = $(arch_hdrdir)/ruby:$(hdrdir)/ruby:$(srcdir):$(srcdir)/missing empty = diff --git a/template/id.c.tmpl b/template/id.c.tmpl index 5b9e8797303341..5aa8e47ce7372b 100644 --- a/template/id.c.tmpl +++ b/template/id.c.tmpl @@ -22,7 +22,8 @@ ops = ids[:token_op].uniq {|id, op, token| token && op} static const struct { unsigned short token; - const char name[3], term; + RBIMPL_ATTR_NONSTRING() const char name[3]; + const char term; } op_tbl[] = { % ops.each do |_id, op, token| % next unless token diff --git a/template/prelude.c.tmpl b/template/prelude.c.tmpl index 74f6c08da7973e..1f0910de189264 100644 --- a/template/prelude.c.tmpl +++ b/template/prelude.c.tmpl @@ -93,6 +93,7 @@ Prelude.new(output, ARGV, vpath).instance_eval do #include "internal/ruby_parser.h" #include "internal/warnings.h" #include "iseq.h" +#include "ruby/internal/attr/nonstring.h" #include "ruby/ruby.h" #include "vm_core.h" @@ -112,12 +113,12 @@ static const struct { % size += line.size % next % end - char L<%=beg%><%=%>[<%=size%><%=%>]; /* <%=beg+1%>..<%=n%> */ + RBIMPL_ATTR_NONSTRING() char L<%=beg%><%=%>[<%=size%><%=%>]; /* <%=beg+1%>..<%=n%> */ % size = line.size % beg = n % } % if size > 0 - char L<%=beg%><%=%>[<%=size%><%=%>]; /* <%=beg+1%>..<%=lines.size+1%> */ + RBIMPL_ATTR_NONSTRING() char L<%=beg%><%=%>[<%=size%><%=%>]; /* <%=beg+1%>..<%=lines.size+1%> */ % end } prelude_code<%=i%><%=%> = { % size = 0 diff --git a/test/-ext-/debug/test_debug.rb b/test/-ext-/debug/test_debug.rb index 8a351d74fad975..a6e0af23142657 100644 --- a/test/-ext-/debug/test_debug.rb +++ b/test/-ext-/debug/test_debug.rb @@ -72,4 +72,19 @@ def test_lazy_block end assert_equal true, x, '[Bug #15105]' end + + # This is a YJIT test, but we can't test this without a C extension that calls + # rb_debug_inspector_open(), so we're testing it using "-test-/debug" here. + def test_yjit_invalidates_setlocal_after_inspector_call + val = setlocal_after_proc_call(proc { Bug::Debug.inspector; :ok }) + assert_equal :ok, val + end if defined?(RubyVM::YJIT) && RubyVM::YJIT.enabled? + + private + + def setlocal_after_proc_call(block) + local = block.call # setlocal followed by OPTIMIZED_METHOD_TYPE_CALL + itself # split a block using a C call + local # getlocal + end end diff --git a/test/coverage/test_coverage.rb b/test/coverage/test_coverage.rb index 16be47b458b0b1..4751bec6d543e8 100644 --- a/test/coverage/test_coverage.rb +++ b/test/coverage/test_coverage.rb @@ -181,6 +181,23 @@ def test_eval_coverage end; end + def test_eval_negative_lineno + assert_in_out_err(["-rcoverage"], <<-"end;", ["[1, 1, 1]"], []) + Coverage.start(eval: true, lines: true) + + eval(<<-RUBY, TOPLEVEL_BINDING, "test.rb", -2) + p # -2 # Not subject to measurement + p # -1 # Not subject to measurement + p # 0 # Not subject to measurement + p # 1 # Subject to measurement + p # 2 # Subject to measurement + p # 3 # Subject to measurement + RUBY + + p Coverage.result["test.rb"][:lines] + end; + end + def test_coverage_supported assert Coverage.supported?(:lines) assert Coverage.supported?(:oneshot_lines) diff --git a/test/date/test_date.rb b/test/date/test_date.rb index 3f9c893efa6f35..7e37fc94d2644b 100644 --- a/test/date/test_date.rb +++ b/test/date/test_date.rb @@ -134,6 +134,10 @@ def test_hash assert_equal(9, h[Date.new(1999,5,25)]) assert_equal(9, h[DateTime.new(1999,5,25)]) + h = {} + h[Date.new(3171505571716611468830131104691,2,19)] = 0 + assert_equal(true, h.key?(Date.new(3171505571716611468830131104691,2,19))) + h = {} h[DateTime.new(1999,5,23)] = 0 h[DateTime.new(1999,5,24)] = 1 diff --git a/test/resolv/test_dns.rb b/test/resolv/test_dns.rb index 20c3408cd6b9ca..c25026eb4c9091 100644 --- a/test/resolv/test_dns.rb +++ b/test/resolv/test_dns.rb @@ -589,6 +589,13 @@ def test_too_big_label_address assert_operator(2**14, :<, m.to_s.length) end + def test_too_long_address + too_long_address_message = [0, 0, 1, 0, 0, 0].pack("n*") + "\x01x" * 129 + [0, 0, 0].pack("cnn") + assert_raise_with_message(Resolv::DNS::DecodeError, /name label data exceed 255 octets/) do + Resolv::DNS::Message.decode too_long_address_message + end + end + def assert_no_fd_leak socket = assert_throw(self) do |tag| Resolv::DNS.stub(:bind_random_port, ->(s, *) {throw(tag, s)}) do diff --git a/test/ruby/test_data.rb b/test/ruby/test_data.rb index bb38f8ec919f33..dd698fdcc4a30e 100644 --- a/test/ruby/test_data.rb +++ b/test/ruby/test_data.rb @@ -280,4 +280,10 @@ def test_marshal assert_not_same(test, loaded) assert_predicate(loaded, :frozen?) end + + def test_frozen_subclass + test = Class.new(Data.define(:a)).freeze.new(a: 0) + assert_kind_of(Data, test) + assert_equal([:a], test.members) + end end diff --git a/test/ruby/test_exception.rb b/test/ruby/test_exception.rb index 07b39d1217e50f..b1d671e2e4cccc 100644 --- a/test/ruby/test_exception.rb +++ b/test/ruby/test_exception.rb @@ -1459,6 +1459,15 @@ def test_detailed_message assert_equal("\e[1mRuntimeError (\e[1;4mRuntimeError\e[m\e[1m)\e[m", e.detailed_message(highlight: true)) end + def test_detailed_message_under_gc_compact_stress + omit "compaction doesn't work well on s390x" if RUBY_PLATFORM =~ /s390x/ # https://github.com/ruby/ruby/pull/5077 + EnvUtil.under_gc_compact_stress do + e = RuntimeError.new("foo\nbar\nbaz") + assert_equal("foo (RuntimeError)\nbar\nbaz", e.detailed_message) + assert_equal("\e[1mfoo (\e[1;4mRuntimeError\e[m\e[1m)\e[m\n\e[1mbar\e[m\n\e[1mbaz\e[m", e.detailed_message(highlight: true)) + end + end + def test_full_message_with_custom_detailed_message e = RuntimeError.new("message") opt_ = nil diff --git a/test/ruby/test_hash.rb b/test/ruby/test_hash.rb index 2d36556953ab3b..6fa808710071ce 100644 --- a/test/ruby/test_hash.rb +++ b/test/ruby/test_hash.rb @@ -1268,6 +1268,17 @@ def test_update5 assert_equal(@cls[a: 10, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8, i: 9, j: 10], h) end + def test_update_modify_in_block + a = @cls[] + (1..1337).each {|k| a[k] = k} + b = {1=>1338} + assert_raise_with_message(RuntimeError, /rehash during iteration/) do + a.update(b) {|k, o, n| + a.rehash + } + end + end + def test_update_on_identhash key = +'a' i = @cls[].compare_by_identity @@ -1816,6 +1827,14 @@ def test_transform_values_bang end end assert_equal(@cls[a: 2, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8, i: 9, j: 10], x) + + x = (1..1337).to_h {|k| [k, k]} + assert_raise_with_message(RuntimeError, /rehash during iteration/) do + x.transform_values! {|v| + x.rehash if v == 1337 + v * 2 + } + end end def hrec h, n, &b @@ -2296,6 +2315,11 @@ def test_bug_12706 end end + def test_bug_21357 + h = {x: []}.merge(x: nil) { |_k, v1, _v2| v1 } + assert_equal({x: []}, h) + end + def test_any_hash_fixable 20.times do assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") diff --git a/test/ruby/test_marshal.rb b/test/ruby/test_marshal.rb index c27de3524e189e..2c5985f1d72937 100644 --- a/test/ruby/test_marshal.rb +++ b/test/ruby/test_marshal.rb @@ -268,7 +268,11 @@ def test_symlink_in_ivar classISO8859_1.name ClassISO8859_1 = classISO8859_1 - def test_class_nonascii + moduleUTF8 = const_set("C\u{30af 30e9 30b9}", Module.new) + moduleUTF8.name + ModuleUTF8 = moduleUTF8 + + def test_nonascii_class_instance a = ClassUTF8.new assert_instance_of(ClassUTF8, Marshal.load(Marshal.dump(a)), '[ruby-core:24790]') @@ -301,6 +305,12 @@ def test_class_nonascii end end + def test_nonascii_class_module + assert_same(ClassUTF8, Marshal.load(Marshal.dump(ClassUTF8))) + assert_same(ClassISO8859_1, Marshal.load(Marshal.dump(ClassISO8859_1))) + assert_same(ModuleUTF8, Marshal.load(Marshal.dump(ModuleUTF8))) + end + def test_regexp2 assert_equal(/\\u/, Marshal.load("\004\b/\b\\\\u\000")) assert_equal(/u/, Marshal.load("\004\b/\a\\u\000")) diff --git a/test/ruby/test_string.rb b/test/ruby/test_string.rb index a916781fe80f85..41a6a400030f9c 100644 --- a/test/ruby/test_string.rb +++ b/test/ruby/test_string.rb @@ -1908,6 +1908,13 @@ def test_split_with_block result = []; S("aaa,bbb,ccc,ddd").split(/,/) {|s| result << s.gsub(/./, "A")} assert_equal(["AAA"]*4, result) + + s = S("abc ") * 20 + assert_raise(RuntimeError) { + 10.times do + s.split {s.prepend("xxx" * 100)} + end + } ensure EnvUtil.suppress_warning {$; = fs} end diff --git a/test/ruby/test_struct.rb b/test/ruby/test_struct.rb index 3d727adf04eb32..e6fd6af8eccb7c 100644 --- a/test/ruby/test_struct.rb +++ b/test/ruby/test_struct.rb @@ -548,6 +548,12 @@ def test_named_structs_are_not_rooted CODE end + def test_frozen_subclass + test = Class.new(@Struct.new(:a)).freeze.new(a: 0) + assert_kind_of(@Struct, test) + assert_equal([:a], test.members) + end + class TopStruct < Test::Unit::TestCase include TestStruct diff --git a/test/ruby/test_variable.rb b/test/ruby/test_variable.rb index 86f2e4bb84d3e9..fc2580654dafc8 100644 --- a/test/ruby/test_variable.rb +++ b/test/ruby/test_variable.rb @@ -393,20 +393,38 @@ def initialize @a = 1 @b = 2 @c = 3 + @d = 4 + @e = 5 + @f = 6 + @g = 7 + @h = 8 end def ivars - [@a, @b, @c] + [@a, @b, @c, @d, @e, @f, @g, @h] end end def test_external_ivars 3.times{ # check inline cache for external ivar access - assert_equal [1, 2, 3], ExIvar.new.ivars + assert_equal [1, 2, 3, 4, 5, 6, 7, 8], ExIvar.new.ivars } end + def test_exivar_resize_with_compaction_stress + objs = 10_000.times.map do + ExIvar.new + end + EnvUtil.under_gc_compact_stress do + 10.times do + x = ExIvar.new + x.instance_variable_set(:@resize, 1) + x + end + end + end + def test_local_variables_with_kwarg bug11674 = '[ruby-core:71437] [Bug #11674]' v = with_kwargs_11(v1:1,v2:2,v3:3,v4:4,v5:5,v6:6,v7:7,v8:8,v9:9,v10:10,v11:11) diff --git a/thread.c b/thread.c index bcafbaacfaab9b..51316c100e9219 100644 --- a/thread.c +++ b/thread.c @@ -5589,6 +5589,7 @@ update_line_coverage(VALUE data, const rb_trace_arg_t *trace_arg) VALUE lines = RARRAY_AREF(coverage, COVERAGE_INDEX_LINES); if (lines) { long line = rb_sourceline() - 1; + VM_ASSERT(line >= 0); long count; VALUE num; void rb_iseq_clear_event_flags(const rb_iseq_t *iseq, size_t pos, rb_event_flag_t reset); diff --git a/tool/downloader.rb b/tool/downloader.rb index 2398fd7b046ecd..82421e4f1dddf2 100644 --- a/tool/downloader.rb +++ b/tool/downloader.rb @@ -215,9 +215,6 @@ def self.download(url, name, dir = nil, since = true, options = {}) $stdout.puts "#{file} already exists" $stdout.flush end - if cache_save - save_cache(cache, file, name) - end return file.to_path end if dryrun diff --git a/variable.c b/variable.c index f8cf7d735e9222..6161873a607dc2 100644 --- a/variable.c +++ b/variable.c @@ -1162,22 +1162,6 @@ gen_ivtbl_bytes(size_t n) return offsetof(struct gen_ivtbl, as.shape.ivptr) + n * sizeof(VALUE); } -static struct gen_ivtbl * -gen_ivtbl_resize(struct gen_ivtbl *old, uint32_t n) -{ - RUBY_ASSERT(n > 0); - - uint32_t len = old ? old->as.shape.numiv : 0; - struct gen_ivtbl *ivtbl = xrealloc(old, gen_ivtbl_bytes(n)); - - ivtbl->as.shape.numiv = n; - for (; len < n; len++) { - ivtbl->as.shape.ivptr[len] = Qundef; - } - - return ivtbl; -} - void rb_mark_generic_ivar(VALUE obj) { @@ -1632,41 +1616,6 @@ struct gen_ivar_lookup_ensure_size { bool resize; }; -static int -generic_ivar_lookup_ensure_size(st_data_t *k, st_data_t *v, st_data_t u, int existing) -{ - ASSERT_vm_locking(); - - struct gen_ivar_lookup_ensure_size *ivar_lookup = (struct gen_ivar_lookup_ensure_size *)u; - struct gen_ivtbl *ivtbl = existing ? (struct gen_ivtbl *)*v : NULL; - - if (!existing || ivar_lookup->resize) { - if (existing) { - RUBY_ASSERT(ivar_lookup->shape->type == SHAPE_IVAR); - RUBY_ASSERT(rb_shape_get_shape_by_id(ivar_lookup->shape->parent_id)->capacity < ivar_lookup->shape->capacity); - } - else { - FL_SET_RAW((VALUE)*k, FL_EXIVAR); - } - - ivtbl = gen_ivtbl_resize(ivtbl, ivar_lookup->shape->capacity); - *v = (st_data_t)ivtbl; - } - - RUBY_ASSERT(FL_TEST((VALUE)*k, FL_EXIVAR)); - - ivar_lookup->ivtbl = ivtbl; - if (ivar_lookup->shape) { -#if SHAPE_IN_BASIC_FLAGS - rb_shape_set_shape(ivar_lookup->obj, ivar_lookup->shape); -#else - ivtbl->shape_id = rb_shape_id(ivar_lookup->shape); -#endif - } - - return ST_CONTINUE; -} - static VALUE * generic_ivar_set_shape_ivptr(VALUE obj, void *data) { @@ -1674,9 +1623,48 @@ generic_ivar_set_shape_ivptr(VALUE obj, void *data) struct gen_ivar_lookup_ensure_size *ivar_lookup = data; + // We can't use st_update, since when resizing the fields table GC can + // happen, which will modify the st_table and may rebuild it RB_VM_LOCK_ENTER(); { - st_update(generic_ivtbl(obj, ivar_lookup->id, false), (st_data_t)obj, generic_ivar_lookup_ensure_size, (st_data_t)ivar_lookup); + struct gen_ivtbl *ivtbl = NULL; + st_table *tbl = generic_ivtbl(obj, ivar_lookup->id, false); + int existing = st_lookup(tbl, (st_data_t)obj, (st_data_t *)&ivtbl); + + if (!existing || ivar_lookup->resize) { + uint32_t new_capa = ivar_lookup->shape->capacity; + uint32_t old_capa = rb_shape_get_shape_by_id(ivar_lookup->shape->parent_id)->capacity; + + if (existing) { + RUBY_ASSERT(ivar_lookup->shape->type == SHAPE_IVAR); + RUBY_ASSERT(old_capa < new_capa); + RUBY_ASSERT(ivtbl); + } else { + RUBY_ASSERT(!ivtbl); + RUBY_ASSERT(old_capa == 0); + } + RUBY_ASSERT(new_capa > 0); + + struct gen_ivtbl *old_ivtbl = ivtbl; + ivtbl = xmalloc(gen_ivtbl_bytes(new_capa)); + if (old_ivtbl) { + memcpy(ivtbl, old_ivtbl, gen_ivtbl_bytes(old_capa)); + } + ivtbl->as.shape.numiv = new_capa; + for (uint32_t i = old_capa; i < new_capa; i++) { + ivtbl->as.shape.ivptr[i] = Qundef; + } + + st_insert(tbl, (st_data_t)obj, (st_data_t)ivtbl); + if (old_ivtbl) { + xfree(old_ivtbl); + } + } + + ivar_lookup->ivtbl = ivtbl; + if (ivar_lookup->shape) { + rb_shape_set_shape(ivar_lookup->obj, ivar_lookup->shape); + } } RB_VM_LOCK_LEAVE(); @@ -2134,8 +2122,8 @@ rb_copy_generic_ivar(VALUE clone, VALUE obj) new_ivtbl->as.complex.table = st_copy(obj_ivtbl->as.complex.table); } else { - new_ivtbl = gen_ivtbl_resize(0, obj_ivtbl->as.shape.numiv); - + new_ivtbl = xmalloc(gen_ivtbl_bytes(obj_ivtbl->as.shape.numiv)); + new_ivtbl->as.shape.numiv = obj_ivtbl->as.shape.numiv; for (uint32_t i=0; ias.shape.numiv; i++) { RB_OBJ_WRITE(clone, &new_ivtbl->as.shape.ivptr[i], obj_ivtbl->as.shape.ivptr[i]); } diff --git a/version.h b/version.h index e8b1c04d693918..3a47f472d14372 100644 --- a/version.h +++ b/version.h @@ -9,9 +9,9 @@ */ # define RUBY_VERSION_MAJOR RUBY_API_VERSION_MAJOR # define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR -#define RUBY_VERSION_TEENY 8 +#define RUBY_VERSION_TEENY 9 #define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR -#define RUBY_PATCHLEVEL 144 +#define RUBY_PATCHLEVEL 170 #include "ruby/version.h" #include "ruby/internal/abi.h" diff --git a/vm.c b/vm.c index 9fb7cb017f05e1..9585135dff5053 100644 --- a/vm.c +++ b/vm.c @@ -3528,10 +3528,10 @@ rb_ec_initialize_vm_stack(rb_execution_context_t *ec, VALUE *stack, size_t size) void rb_ec_clear_vm_stack(rb_execution_context_t *ec) { - rb_ec_set_vm_stack(ec, NULL, 0); - - // Avoid dangling pointers: + // set cfp to NULL before clearing the stack in case `thread_profile_frames` + // gets called in this middle of `rb_ec_set_vm_stack` via signal handler. ec->cfp = NULL; + rb_ec_set_vm_stack(ec, NULL, 0); } static void diff --git a/win32/Makefile.sub b/win32/Makefile.sub index 21dbd05812ae53..b9c31f4b53c88d 100644 --- a/win32/Makefile.sub +++ b/win32/Makefile.sub @@ -281,6 +281,10 @@ WARNFLAGS = -W2 -wd4100 -wd4127 -wd4210 -wd4214 -wd4255 -wd4574 \ !else WARNFLAGS = -W2 !endif +!if $(MSC_VER) >= 1944 +# https://developercommunity.visualstudio.com/t/warning-C5287:-operands-are-different-e/10877942 +WARNFLAGS = $(WARNFLAGS) -wd5287 +!endif !endif WERRORFLAG = -WX !if !defined(CFLAGS_NO_ARCH) @@ -487,7 +491,8 @@ ENCOBJS = dmyenc.$(OBJEXT) EXTOBJS = dmyext.$(OBJEXT) !endif -arch_hdrdir = $(EXTOUT)/include/$(arch) +ext_hdrdir = $(EXTOUT)/include +arch_hdrdir = $(ext_hdrdir)/$(arch) top_srcdir = $(srcdir) hdrdir = $(srcdir)/include tooldir = $(srcdir)/tool @@ -1399,8 +1404,6 @@ loadpath: verconf.h sed -e '1,/^const char ruby_initial_load_paths/d;/;/,$$d' \ -e '/^^ /!d;s/ *"\\\\0"$$//;s/" *"//g' -RUBYSPEC_CAPIEXT_SRCDIR = $(srcdir)/$(RUBYSPEC_CAPIEXT) -RUBYSPEC_CAPIEXT_DEPS = $(RUBYSPEC_CAPIEXT_SRCDIR)/rubyspec.h $(RUBY_H_INCLUDES) $(LIBRUBY) RUBYSPEC_CAPIEXT_EXTS = !if [echo>rubyspec-capiext.mk RUBYSPEC_CAPIEXT_EXTS = \] diff --git a/win32/mkexports.rb b/win32/mkexports.rb index dd0fbf6313154f..0c6db1de114f7b 100755 --- a/win32/mkexports.rb +++ b/win32/mkexports.rb @@ -114,6 +114,7 @@ def each_export(objs) case filetype when /OBJECT/, /LIBRARY/ l.chomp! + next if (/^ .*\(pick any\)$/ =~ l)...true next if /^[[:xdigit:]]+ 0+ UNDEF / =~ l next unless /External/ =~ l next if /(?:_local_stdio_printf_options|v(f|sn?)printf(_s)?_l)\Z/ =~ l diff --git a/win32/win32.c b/win32/win32.c index c51d53595fc70e..8dd96981adadff 100644 --- a/win32/win32.c +++ b/win32/win32.c @@ -4832,10 +4832,11 @@ waitpid(rb_pid_t pid, int *stat_loc, int options) static int have_precisetime = -1; -static void -get_systemtime(FILETIME *ft) +typedef void (WINAPI *get_time_func)(FILETIME *ft); + +static get_time_func +get_systemtime_func(void) { - typedef void (WINAPI *get_time_func)(FILETIME *ft); static get_time_func func = (get_time_func)-1; if (func == (get_time_func)-1) { @@ -4848,8 +4849,14 @@ get_systemtime(FILETIME *ft) else have_precisetime = 1; } + return func; +} + +static void +get_systemtime(FILETIME *ft) +{ if (!ft) return; - func(ft); + get_systemtime_func()(ft); } /* License: Ruby's */ @@ -4889,6 +4896,7 @@ gettimeofday(struct timeval *tv, struct timezone *tz) return 0; } +#if !defined(__MINGW32__) || !defined(HAVE_CLOCK_GETTIME) /* License: Ruby's */ int clock_gettime(clockid_t clock_id, struct timespec *sp) @@ -4928,7 +4936,9 @@ clock_gettime(clockid_t clock_id, struct timespec *sp) return -1; } } +#endif +#if !defined(__MINGW32__) || !defined(HAVE_CLOCK_GETRES) /* License: Ruby's */ int clock_getres(clockid_t clock_id, struct timespec *sp) @@ -4956,6 +4966,7 @@ clock_getres(clockid_t clock_id, struct timespec *sp) return -1; } } +#endif /* License: Ruby's */ static char * @@ -5766,6 +5777,7 @@ stati128_handle(HANDLE h, struct stati128 *st) if (GetFileInformationByHandle(h, &info)) { FILE_ID_INFO fii; + get_systemtime_func(); st->st_size = ((__int64)info.nFileSizeHigh << 32) | info.nFileSizeLow; st->st_atime = filetime_to_unixtime(&info.ftLastAccessTime); st->st_atimensec = filetime_to_nsec(&info.ftLastAccessTime); @@ -5911,6 +5923,7 @@ stat_by_find(const WCHAR *path, struct stati128 *st) return -1; } FindClose(h); + get_systemtime_func(); st->st_mode = fileattr_to_unixmode(wfd.dwFileAttributes, path, 0); st->st_atime = filetime_to_unixtime(&wfd.ftLastAccessTime); st->st_atimensec = filetime_to_nsec(&wfd.ftLastAccessTime); diff --git a/yjit/src/codegen.rs b/yjit/src/codegen.rs index d702b1133e1847..1d1e59161e101c 100644 --- a/yjit/src/codegen.rs +++ b/yjit/src/codegen.rs @@ -7449,7 +7449,6 @@ fn gen_send_general( } OPTIMIZED_METHOD_TYPE_CALL => { - if block.is_some() { gen_counter_incr(asm, Counter::send_call_block); return None; @@ -7501,8 +7500,10 @@ fn gen_send_general( let stack_ret = asm.stack_push(Type::Unknown); asm.mov(stack_ret, ret); - return Some(KeepCompiling); + // End the block to allow invalidating the next instruction + jump_to_next_insn(jit, asm, ocb); + return Some(EndBlock); } OPTIMIZED_METHOD_TYPE_BLOCK_CALL => { gen_counter_incr(asm, Counter::send_optimized_method_block_call); diff --git a/yjit/src/core.rs b/yjit/src/core.rs index 064a7b5e8f772c..a13d3c13b7fd73 100644 --- a/yjit/src/core.rs +++ b/yjit/src/core.rs @@ -3232,7 +3232,23 @@ pub fn invalidate_block_version(blockref: &BlockRef) { } // For each incoming branch - for branchref in block.incoming.0.take().iter() { + let mut incoming_branches = block.incoming.0.take(); + + // An adjacent branch will write into the start of the block being invalidated, possibly + // overwriting the block's exit. If we run out of memory after doing this, any subsequent + // incoming branches we rewrite won't be able use the block's exit as a fallback when they + // are unable to generate a stub. To avoid this, if there's an incoming branch that's + // adjacent to the invalidated block, make sure we process it last. + let adjacent_branch_idx = incoming_branches.iter().position(|branchref| { + let branch = unsafe { branchref.as_ref() }; + let target_next = block.start_addr == branch.end_addr.get(); + target_next + }); + if let Some(adjacent_branch_idx) = adjacent_branch_idx { + incoming_branches.swap(adjacent_branch_idx, incoming_branches.len() - 1) + } + + for (i, branchref) in incoming_branches.iter().enumerate() { let branch = unsafe { branchref.as_ref() }; let target_idx = if branch.get_target_address(0) == Some(block_start) { 0 @@ -3272,10 +3288,18 @@ pub fn invalidate_block_version(blockref: &BlockRef) { let target_next = block.start_addr == branch.end_addr.get(); if target_next { - // The new block will no longer be adjacent. - // Note that we could be enlarging the branch and writing into the - // start of the block being invalidated. - branch.gen_fn.set_shape(BranchShape::Default); + if stub_addr != block.start_addr { + // The new block will no longer be adjacent. + // Note that we could be enlarging the branch and writing into the + // start of the block being invalidated. + branch.gen_fn.set_shape(BranchShape::Default); + } else { + // The branch target is still adjacent, so the branch must remain + // a fallthrough so we don't overwrite the target with a jump. + // + // This can happen if we're unable to generate a stub and the + // target block also exits on entry (block_start == block_entry_exit). + } } // Rewrite the branch with the new jump target address @@ -3285,6 +3309,11 @@ pub fn invalidate_block_version(blockref: &BlockRef) { if target_next && branch.end_addr > block.end_addr { panic!("yjit invalidate rewrote branch past end of invalidated block: {:?} (code_size: {})", branch, block.code_size()); } + let is_last_incoming_branch = i == incoming_branches.len() - 1; + if target_next && branch.end_addr.get() > block_entry_exit && !is_last_incoming_branch { + // We might still need to jump to this exit if we run out of memory when rewriting another incoming branch. + panic!("yjit invalidate rewrote branch over exit of invalidated block: {:?}", branch); + } if !target_next && branch.code_size() > old_branch_size { panic!( "invalidated branch grew in size (start_addr: {:?}, old_size: {}, new_size: {})",