From 90f74e0672b25b4102b311b69bf3beca3e00907c Mon Sep 17 00:00:00 2001 From: Jean Boussier Date: Tue, 31 Mar 2026 02:24:42 +0100 Subject: [PATCH 01/14] [ruby/strscan] Implement compaction and embedded structs (https://github.com/ruby/strscan/pull/201) GC compaction was introduced in Ruby 2.7. Embedded Structs was introduced in Ruby 3.3. When enabled, the `struct strscanner` is stored directly inside the object slot, meaning reading the struct member doesn't require loading another memory region. https://github.com/ruby/strscan/commit/a018cbe40e --- ext/strscan/extconf.rb | 2 ++ ext/strscan/strscan.c | 52 +++++++++++++++++++++++++++++++++++------- 2 files changed, 46 insertions(+), 8 deletions(-) diff --git a/ext/strscan/extconf.rb b/ext/strscan/extconf.rb index d2e9343cbced7f..2b4ec25be30909 100644 --- a/ext/strscan/extconf.rb +++ b/ext/strscan/extconf.rb @@ -5,6 +5,8 @@ have_func("onig_region_memsize(NULL)") have_func("rb_reg_onig_match", "ruby/re.h") have_func("rb_deprecate_constant") + have_func("rb_gc_location", "ruby.h") # RUBY_VERSION >= 2.7 + have_const("RUBY_TYPED_EMBEDDABLE", "ruby.h") # RUBY_VERSION >= 3.3 create_makefile 'strscan' else File.write('Makefile', dummy_makefile("").join) diff --git a/ext/strscan/strscan.c b/ext/strscan/strscan.c index 93c0c04631a637..7efee0b5db4d1e 100644 --- a/ext/strscan/strscan.c +++ b/ext/strscan/strscan.c @@ -182,12 +182,35 @@ extract_beg_len(struct strscanner *p, long beg_i, long len) Constructor ======================================================================= */ +#ifdef RUBY_TYPED_EMBEDDABLE +# define HAVE_RUBY_TYPED_EMBEDDABLE 1 +#else +# ifdef HAVE_CONST_RUBY_TYPED_EMBEDDABLE +# define RUBY_TYPED_EMBEDDABLE RUBY_TYPED_EMBEDDABLE +# define HAVE_RUBY_TYPED_EMBEDDABLE 1 +# else +# define RUBY_TYPED_EMBEDDABLE 0 +# endif +#endif + +#ifdef HAVE_RB_GC_LOCATION +static void +strscan_compact(void *ptr) +{ + struct strscanner *p = ptr; + p->str = rb_gc_location(p->str); + p->regex = rb_gc_location(p->regex); +} +#else +#define rb_gc_mark_movable rb_gc_mark +#endif + static void strscan_mark(void *ptr) { struct strscanner *p = ptr; - rb_gc_mark(p->str); - rb_gc_mark(p->regex); + rb_gc_mark_movable(p->str); + rb_gc_mark_movable(p->regex); } static void @@ -195,24 +218,37 @@ strscan_free(void *ptr) { struct strscanner *p = ptr; onig_region_free(&(p->regs), 0); +#ifndef HAVE_RUBY_TYPED_EMBEDDABLE ruby_xfree(p); +#endif } static size_t strscan_memsize(const void *ptr) { - const struct strscanner *p = ptr; - size_t size = sizeof(*p) - sizeof(p->regs); + size_t size = 0; +#ifndef HAVE_RUBY_TYPED_EMBEDDABLE + size += sizeof(struct strscanner); +#endif + #ifdef HAVE_ONIG_REGION_MEMSIZE - size += onig_region_memsize(&p->regs); + const struct strscanner *p = ptr; + size += onig_region_memsize(&p->regs) - sizeof(p->regs); #endif return size; } static const rb_data_type_t strscanner_type = { - "StringScanner", - {strscan_mark, strscan_free, strscan_memsize}, - 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED + .wrap_struct_name = "StringScanner", + .function = { + .dmark = strscan_mark, + .dfree = strscan_free, + .dsize = strscan_memsize, +#ifdef HAVE_RB_GC_LOCATION + .dcompact = strscan_compact, +#endif + }, + .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE }; static VALUE From 3c251f79a3d98259e7a5a60d8483b33c9a65728a Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Thu, 26 Mar 2026 00:31:41 -0700 Subject: [PATCH 02/14] Don't add singleton classes to subclasses list Singleton classes don't need to be iterated in the subclasses list, we only need to know that a subclass exists so that we can use the "method entry" path for invalidation. --- class.c | 19 ++++++++++++++++--- internal/class.h | 1 + vm_method.c | 1 + 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/class.c b/class.c index 35b66be920f7a0..8a144b8cab9cc5 100644 --- a/class.c +++ b/class.c @@ -743,7 +743,15 @@ class_associate_super(VALUE klass, VALUE super, bool init) // Include/prepend inserts ICLASSes into the super chain, but T_CLASS // subclass lists should track only the immutable T_CLASS→T_CLASS link. if (RB_TYPE_P(klass, T_CLASS) && RB_TYPE_P(super, T_CLASS)) { - class_switch_superclass(super, klass); + if (RCLASS_SINGLETON_P(klass)) { + // Instead of adding singleton classes to the subclass list, + // just set a flag so that method cache invalidation takes the + // tree path. + FL_SET_RAW(super, RCLASS_HAS_SUBCLASSES); + } + else { + class_switch_superclass(super, klass); + } } } if (init) { @@ -1328,9 +1336,14 @@ static inline VALUE make_singleton_class(VALUE obj) { VALUE orig_class = METACLASS_OF(obj); - VALUE klass = class_boot_boxable(orig_class, FL_TEST_RAW(orig_class, RCLASS_BOXABLE)); - + VALUE klass = class_alloc0(T_CLASS, rb_cClass, FL_TEST_RAW(orig_class, RCLASS_BOXABLE)); FL_SET(klass, FL_SINGLETON); + class_initialize_method_table(klass); + class_associate_super(klass, orig_class, true); + if (orig_class && !UNDEF_P(orig_class)) { + rb_class_set_initialized(klass); + } + RBASIC_SET_CLASS(obj, klass); rb_singleton_class_attached(klass, obj); rb_yjit_invalidate_no_singleton_class(orig_class); diff --git a/internal/class.h b/internal/class.h index 5a6dda5d1070f7..5b88712c7cfd39 100644 --- a/internal/class.h +++ b/internal/class.h @@ -256,6 +256,7 @@ static inline void RCLASS_WRITE_CLASSPATH(VALUE klass, VALUE classpath, bool per // 3 is RMODULE_IS_REFINEMENT for RMODULE #define RCLASS_BOXABLE FL_USER4 #define RCLASS_ALLOCATOR_DEFINED FL_USER5 +#define RCLASS_HAS_SUBCLASSES FL_USER6 static inline st_table * RCLASS_CLASSEXT_TBL(VALUE klass) diff --git a/vm_method.c b/vm_method.c index 021b06bf00109b..f6f666a9188076 100644 --- a/vm_method.c +++ b/vm_method.c @@ -440,6 +440,7 @@ clear_method_cache_by_id_in_class(VALUE klass, ID mid) rb_vm_barrier(); if (LIKELY(RCLASS_SUBCLASSES_FIRST(klass) == NULL) && + !FL_TEST_RAW(klass, RCLASS_HAS_SUBCLASSES) && // Non-refinement ICLASSes (from module inclusion) previously had // subclasses reparented onto them, so they need the tree path for // broader cme-based invalidation even though they now have no subclasses. From 1da540aeaa1507af4c050bf8a6ee2802e65f9aac Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Mon, 9 Mar 2026 21:42:12 -0700 Subject: [PATCH 03/14] Invalidate CC on cme free as well --- gc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gc.c b/gc.c index d6d517d6a44c9e..741d6c8c7a0a88 100644 --- a/gc.c +++ b/gc.c @@ -1278,7 +1278,9 @@ rb_gc_handle_weak_references(VALUE obj) GC_ASSERT(imemo_type(obj) == imemo_callcache); struct rb_callcache *cc = (struct rb_callcache *)obj; - if (!rb_gc_handle_weak_references_alive_p(cc->klass)) { + if (cc->klass != Qundef && + (!rb_gc_handle_weak_references_alive_p(cc->klass) || + !rb_gc_handle_weak_references_alive_p((VALUE)cc->cme_))) { vm_cc_invalidate(cc); } From 3b502e62f353807871ab8d110134bd1688b4ad61 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 31 Mar 2026 02:11:02 +0000 Subject: [PATCH 04/14] Bump taiki-e/install-action Bumps the github-actions group with 1 update in the / directory: [taiki-e/install-action](https://github.com/taiki-e/install-action). Updates `taiki-e/install-action` from 2.70.2 to 2.70.3 - [Release notes](https://github.com/taiki-e/install-action/releases) - [Changelog](https://github.com/taiki-e/install-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/taiki-e/install-action/compare/e9e8e031bcd90cdbe8ac6bb1d376f8596e587fbf...6ef672efc2b5aabc787a9e94baf4989aa02a97df) --- updated-dependencies: - dependency-name: taiki-e/install-action dependency-version: 2.70.3 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions ... Signed-off-by: dependabot[bot] --- .github/workflows/zjit-macos.yml | 2 +- .github/workflows/zjit-ubuntu.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/zjit-macos.yml b/.github/workflows/zjit-macos.yml index 40ff83365b4e1c..1cacfbb81f833c 100644 --- a/.github/workflows/zjit-macos.yml +++ b/.github/workflows/zjit-macos.yml @@ -93,7 +93,7 @@ jobs: rustup install ${{ matrix.rust_version }} --profile minimal rustup default ${{ matrix.rust_version }} - - uses: taiki-e/install-action@e9e8e031bcd90cdbe8ac6bb1d376f8596e587fbf # v2.70.2 + - uses: taiki-e/install-action@6ef672efc2b5aabc787a9e94baf4989aa02a97df # v2.70.3 with: tool: nextest@0.9 if: ${{ matrix.test_task == 'zjit-check' }} diff --git a/.github/workflows/zjit-ubuntu.yml b/.github/workflows/zjit-ubuntu.yml index 6c2f4f414c67d7..d4b30409ee0572 100644 --- a/.github/workflows/zjit-ubuntu.yml +++ b/.github/workflows/zjit-ubuntu.yml @@ -119,7 +119,7 @@ jobs: ruby-version: '3.1' bundler: none - - uses: taiki-e/install-action@e9e8e031bcd90cdbe8ac6bb1d376f8596e587fbf # v2.70.2 + - uses: taiki-e/install-action@6ef672efc2b5aabc787a9e94baf4989aa02a97df # v2.70.3 with: tool: nextest@0.9 if: ${{ matrix.test_task == 'zjit-check' }} From 409a0a112f37825a980942e880ea409e7b684a6b Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Tue, 31 Mar 2026 10:57:58 +0900 Subject: [PATCH 05/14] Suppress zizmor secrets-outside-env audit All committers with write access to this repository are trusted, and fork PRs cannot access secrets by default. There is no threat model that environment-scoped secrets would mitigate here. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/zizmor.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/zizmor.yml b/.github/zizmor.yml index dc96bc4167f8c8..718d9883d71da6 100644 --- a/.github/zizmor.yml +++ b/.github/zizmor.yml @@ -23,6 +23,9 @@ rules: unpinned-images: ignore: - compilers.yml + secrets-outside-env: + # All committers with write access are trusted; no need for environment-scoped secrets. + disable: true unpinned-uses: ignore: - cygwin.yml From b2562525c3327455c2a2d4104dbe6a756a4f738a Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Tue, 31 Mar 2026 11:02:09 +0900 Subject: [PATCH 06/14] Exclude test directories from CodeQL analysis CodeQL's Ruby extractor cannot parse UTF-16 encoded fixtures, TRICK entries, and some edge-case syntax in test files, causing 84 parse error warnings. These directories (spec/, test/, sample/, benchmark/) are not relevant for security scanning. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/codeql/codeql-config.yml | 5 +++++ .github/workflows/check_sast.yml | 1 + 2 files changed, 6 insertions(+) create mode 100644 .github/codeql/codeql-config.yml diff --git a/.github/codeql/codeql-config.yml b/.github/codeql/codeql-config.yml new file mode 100644 index 00000000000000..89b22b938e9713 --- /dev/null +++ b/.github/codeql/codeql-config.yml @@ -0,0 +1,5 @@ +paths-ignore: + - benchmark + - sample + - spec + - test diff --git a/.github/workflows/check_sast.yml b/.github/workflows/check_sast.yml index 3c961c93d2293e..6b853b8944e793 100644 --- a/.github/workflows/check_sast.yml +++ b/.github/workflows/check_sast.yml @@ -82,6 +82,7 @@ jobs: with: languages: ${{ matrix.language }} build-mode: none + config-file: .github/codeql/codeql-config.yml - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@c10b8064de6f491fea524254123dbe5e09572f13 # v4.35.1 From d47d97c93856b2509c8051b19734a5d075ee85ca Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Tue, 31 Mar 2026 11:41:43 +0900 Subject: [PATCH 07/14] Add top-level permissions to workflows missing them Restrict the default GITHUB_TOKEN permissions to contents:read for workflows that had no top-level permissions block, as flagged by Scorecard's TokenPermissionsID check. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/labeler.yml | 3 +++ .github/workflows/post_push.yml | 4 ++++ .github/workflows/pr-playground.yml | 3 +++ .github/workflows/publish.yml | 3 +++ .github/workflows/release.yml | 3 +++ .github/workflows/sync_default_gems.yml | 3 +++ .github/workflows/wsl.yml | 3 +++ 7 files changed, 22 insertions(+) diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml index 0d5355f54e56c5..c7eb2865f11485 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/labeler.yml @@ -2,6 +2,9 @@ name: "Pull Request Labeler" on: - pull_request_target +permissions: + contents: read + jobs: labeler: permissions: diff --git a/.github/workflows/post_push.yml b/.github/workflows/post_push.yml index 1352dd2cc7ce30..29736240ae3158 100644 --- a/.github/workflows/post_push.yml +++ b/.github/workflows/post_push.yml @@ -4,6 +4,10 @@ on: branches: - master - 'ruby_*_*' + +permissions: + contents: read + jobs: hooks: name: Post-push hooks diff --git a/.github/workflows/pr-playground.yml b/.github/workflows/pr-playground.yml index 2391656277e4af..e780a08e4d7d34 100644 --- a/.github/workflows/pr-playground.yml +++ b/.github/workflows/pr-playground.yml @@ -6,6 +6,9 @@ on: workflows: ["WebAssembly"] types: [completed] +permissions: + contents: read + jobs: post-summary: name: Post Playground link diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index d7039fd2d153a0..8417192da547cc 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -11,6 +11,9 @@ on: required: true default: '3.3.4' +permissions: + contents: read + jobs: release: runs-on: ubuntu-latest diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c45277abe88a64..a35bcff99af859 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -4,6 +4,9 @@ on: tags: - '*' +permissions: + contents: read + jobs: notify: runs-on: ubuntu-latest diff --git a/.github/workflows/sync_default_gems.yml b/.github/workflows/sync_default_gems.yml index bebcba8c2fe407..6ea9de6fa9fc09 100644 --- a/.github/workflows/sync_default_gems.yml +++ b/.github/workflows/sync_default_gems.yml @@ -19,6 +19,9 @@ on: description: 'Gem commit SHA after sync' type: string +permissions: + contents: read + jobs: sync_default_gems: name: Sync default gem ${{ github.event.inputs.gem }} diff --git a/.github/workflows/wsl.yml b/.github/workflows/wsl.yml index a857c5f4b1458d..189f978e299d3e 100644 --- a/.github/workflows/wsl.yml +++ b/.github/workflows/wsl.yml @@ -14,6 +14,9 @@ on: # https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/collaborating-on-repositories-with-code-quality-features/troubleshooting-required-status-checks#handling-skipped-but-required-checks merge_group: +permissions: + contents: read + jobs: wsl: runs-on: windows-2025 From b956e19ab798bfc1baa796fd08fa18eb626d4ab7 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Tue, 31 Mar 2026 11:50:40 +0900 Subject: [PATCH 08/14] Update pinned action versions in Launchable setup The commit SHAs did not match their version comment tags, as flagged by zizmor ref-version-mismatch. Update all three actions to their latest releases with correct SHAs. - actions/setup-python v5.0.0 -> v5.6.0 - actions/setup-java v4.0.0 -> v4.8.0 - gacts/run-and-post-run v1.4.0 -> v1.4.3 Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/actions/launchable/setup/action.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/actions/launchable/setup/action.yml b/.github/actions/launchable/setup/action.yml index eb9ababd72f063..305878492c243c 100644 --- a/.github/actions/launchable/setup/action.yml +++ b/.github/actions/launchable/setup/action.yml @@ -95,7 +95,7 @@ runs: # Launchable CLI requires Python and Java. # https://www.launchableinc.com/docs/resources/cli-reference/ - name: Set up Python - uses: actions/setup-python@871daa956ca9ea99f3c3e30acb424b7960676734 # v5.0.0 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 with: python-version: "3.x" if: >- @@ -103,7 +103,7 @@ runs: && !endsWith(inputs.os, 'ppc64le') && !endsWith(inputs.os, 's390x') }} - name: Set up Java - uses: actions/setup-java@7a445ee88d4e23b52c33fdc7601e40278616c7f8 # v4.0.0 + uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4.8.0 with: distribution: 'temurin' java-version: '17' @@ -112,7 +112,7 @@ runs: && !endsWith(inputs.os, 'ppc64le') && !endsWith(inputs.os, 's390x') }} - name: Set up Java ppc64le - uses: actions/setup-java@7a445ee88d4e23b52c33fdc7601e40278616c7f8 # v4.0.0 + uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4.8.0 with: distribution: 'semeru' architecture: 'ppc64le' @@ -122,7 +122,7 @@ runs: && endsWith(inputs.os, 'ppc64le') }} - name: Set up Java s390x - uses: actions/setup-java@7a445ee88d4e23b52c33fdc7601e40278616c7f8 # v4.0.0 + uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4.8.0 with: distribution: 'semeru' architecture: 's390x' @@ -270,7 +270,7 @@ runs: test_spec_report_dir: ${{ steps.global.outputs.test_spec_report_dir }} - name: Clean up test results in Launchable - uses: gacts/run-and-post-run@674528335da98a7afc80915ff2b4b860a0b3553a # v1.4.0 + uses: gacts/run-and-post-run@81b6ce503cde93862cec047c54652e45c5dca991 # v1.4.3 with: shell: bash working-directory: ${{ inputs.builddir }} @@ -287,7 +287,7 @@ runs: test_spec_report_dir: ${{ steps.global.outputs.test_spec_report_dir }} - name: Record test results in Launchable - uses: gacts/run-and-post-run@674528335da98a7afc80915ff2b4b860a0b3553a # v1.4.0 + uses: gacts/run-and-post-run@81b6ce503cde93862cec047c54652e45c5dca991 # v1.4.3 with: shell: bash working-directory: ${{ inputs.builddir }} From bd3904f16c1a08ed051e5695112d777882adddeb Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Tue, 31 Mar 2026 11:56:32 +0900 Subject: [PATCH 09/14] Pin cygwin-install-action to v6.1 by commit SHA Replace @master reference with the pinned commit SHA for v6.1, and remove cygwin.yml from the zizmor unpinned-uses ignore list since it is now properly pinned. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/cygwin.yml | 2 +- .github/zizmor.yml | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/cygwin.yml b/.github/workflows/cygwin.yml index 850f654167e41e..5ab86c7b19fbf3 100644 --- a/.github/workflows/cygwin.yml +++ b/.github/workflows/cygwin.yml @@ -45,7 +45,7 @@ jobs: persist-credentials: false - name: Setup Cygwin - uses: cygwin/cygwin-install-action@master + uses: cygwin/cygwin-install-action@711d29f3da23c9f4a1798e369a6f01198c13b11a # v6.1 with: packages: ruby gcc-core make autoconf libtool libssl-devel libyaml-devel libffi-devel zlib-devel rubygems site: | diff --git a/.github/zizmor.yml b/.github/zizmor.yml index 718d9883d71da6..088e616ec1a9e7 100644 --- a/.github/zizmor.yml +++ b/.github/zizmor.yml @@ -28,5 +28,4 @@ rules: disable: true unpinned-uses: ignore: - - cygwin.yml - wsl.yml From 3ae990db84e46d8996c2a8aaf0798aef53a105e6 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Tue, 31 Mar 2026 12:01:01 +0900 Subject: [PATCH 10/14] Remove excessive-permissions from zizmor ignore list These four workflows now have explicit top-level permissions set to contents:read, so the excessive-permissions finding no longer applies. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/zizmor.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/zizmor.yml b/.github/zizmor.yml index 088e616ec1a9e7..53112a28156bba 100644 --- a/.github/zizmor.yml +++ b/.github/zizmor.yml @@ -10,12 +10,6 @@ rules: dependabot-cooldown: ignore: - dependabot.yml - excessive-permissions: - ignore: - - post_push.yml - - publish.yml - - release.yml - - wsl.yml misfeature: ignore: - mingw.yml From bc0320289700ceed79c7ed68494e2c9d5913a540 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Tue, 31 Mar 2026 12:10:25 +0900 Subject: [PATCH 11/14] Add actions:read permission to pr-playground workflow The github-script step calls the Actions API to list workflow runs and download artifacts, which requires actions:read permission. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/pr-playground.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/pr-playground.yml b/.github/workflows/pr-playground.yml index e780a08e4d7d34..097c14bd5cb758 100644 --- a/.github/workflows/pr-playground.yml +++ b/.github/workflows/pr-playground.yml @@ -8,6 +8,7 @@ on: permissions: contents: read + actions: read jobs: post-summary: From c6bee053a2bb07fd5187f88b9312d58244ba390b Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Tue, 31 Mar 2026 12:12:08 +0900 Subject: [PATCH 12/14] Narrow CodeQL paths-ignore to only fixture directories Keep test/ and spec/ in CodeQL analysis for better SAST coverage. Only exclude directories containing intentionally unparseable files such as UTF-16 encoded fixtures and bad syntax test fixtures. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/codeql/codeql-config.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/codeql/codeql-config.yml b/.github/codeql/codeql-config.yml index 89b22b938e9713..d30ad51c7999b6 100644 --- a/.github/codeql/codeql-config.yml +++ b/.github/codeql/codeql-config.yml @@ -1,5 +1,6 @@ paths-ignore: - benchmark - sample - - spec - - test + - spec/ruby/command_line/fixtures + - spec/ruby/core/exception/fixtures + - spec/ruby/language/fixtures From f41c1941a34760d37fbd2c3357cb7a2d42b0d408 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Tue, 31 Mar 2026 12:29:16 +0900 Subject: [PATCH 13/14] pty: Prefer FD-base operations if available --- ext/pty/extconf.rb | 2 ++ ext/pty/pty.c | 27 ++++++++++++++++++++------- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/ext/pty/extconf.rb b/ext/pty/extconf.rb index da3655cf4d7118..ae2cb45d3cabc9 100644 --- a/ext/pty/extconf.rb +++ b/ext/pty/extconf.rb @@ -21,6 +21,8 @@ (util or have_func("openpty")) or have_func("_getpty") or have_func("ioctl") + have_macro("HAVE_FCHMOD") or have_func("fchmod") + have_macro("HAVE_FCHOWN") or have_func("fchown") create_makefile('pty') end end diff --git a/ext/pty/pty.c b/ext/pty/pty.c index 7c79f81e338019..54a8b9d189e598 100644 --- a/ext/pty/pty.c +++ b/ext/pty/pty.c @@ -274,12 +274,23 @@ ptsname_r(int fd, char *buf, size_t buflen) # define HAVE_PTSNAME_R 1 #endif +#ifdef HAVE_FCHMOD +# define change_mode(name, fd, mode) fchmod(fd, mode) +#else +# define change_mode(name, fd, mode) chmod(name, mode) +#endif +#ifdef HAVE_FCHOWN +# define change_owner(name, fd, uid, gid) fchown(fd, uid, gid) +#else +# define change_owner(name, fd, uid, gid) chown(name, uid, gid) +#endif + #if defined(HAVE_POSIX_OPENPT) || defined(HAVE_OPENPTY) || defined(HAVE_PTSNAME_R) static int -no_mesg(char *slavedevice, int nomesg) +set_device_mode(const char *slavedevice, int fd, int nomesg) { if (nomesg) - return chmod(slavedevice, 0600); + return change_mode(slavedevice, fd, 0600); else return 0; } @@ -340,8 +351,8 @@ get_device_once(int *master, int *slave, char SlaveName[DEVICELEN], int nomesg, if (unlockpt(masterfd) == -1) goto error; if (ptsname_r(masterfd, SlaveName, DEVICELEN) != 0) goto error; slavedevice = SlaveName; - if (no_mesg(slavedevice, nomesg) == -1) goto error; if ((slavefd = rb_cloexec_open(slavedevice, O_RDWR|O_NOCTTY, 0)) == -1) goto error; + if (set_device_mode(slavedevice, slavefd, nomesg) == -1) goto error; rb_update_max_fd(slavefd); #if defined(I_PUSH) && !defined(__linux__) && !defined(_AIX) @@ -375,7 +386,9 @@ get_device_once(int *master, int *slave, char SlaveName[DEVICELEN], int nomesg, } rb_fd_fix_cloexec(*master); rb_fd_fix_cloexec(*slave); - if (no_mesg(SlaveName, nomesg) == -1) { + if (set_device_mode(SlaveName, *slave, nomesg) == -1) { + close(*master); + close(*slave); if (!fail) return -1; rb_raise(rb_eRuntimeError, "can't chmod slave pty"); } @@ -424,8 +437,8 @@ get_device_once(int *master, int *slave, char SlaveName[DEVICELEN], int nomesg, if(unlockpt(masterfd) == -1) goto error; if (ptsname_r(masterfd, SlaveName, DEVICELEN) != 0) goto error; slavedevice = SlaveName; - if (no_mesg(slavedevice, nomesg) == -1) goto error; if((slavefd = rb_cloexec_open(slavedevice, O_RDWR, 0)) == -1) goto error; + if (set_device_mode(slavedevice, slavefd, nomesg) == -1) goto error; rb_update_max_fd(slavefd); #if defined(I_PUSH) && !defined(__linux__) && !defined(_AIX) if(ioctl_I_PUSH(slavefd, "ptem") == -1) goto error; @@ -478,8 +491,8 @@ get_device_once(int *master, int *slave, char SlaveName[DEVICELEN], int nomesg, if ((slavefd = rb_cloexec_open(SlaveName,O_RDWR,0)) >= 0) { rb_update_max_fd(slavefd); *slave = slavefd; - if (chown(SlaveName, getuid(), getgid()) != 0) goto error; - if (chmod(SlaveName, nomesg ? 0600 : 0622) != 0) goto error; + if (change_owner(slavefd, getuid(), getgid()) != 0) goto error; + if (change_mode(slavefd, nomesg ? 0600 : 0622) != 0) goto error; return 0; } close(masterfd); From a08f54740a7cfde9b318db8ba59a4de2933c4734 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Tue, 31 Mar 2026 15:13:40 +0900 Subject: [PATCH 14/14] Ignore files with parse errors in CodeQL analysis These test files, specs, and trace_point.rb contain intentionally invalid syntax or special constructs that CodeQL's parser cannot handle. They are not security-relevant and should be excluded from analysis. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/codeql/codeql-config.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/.github/codeql/codeql-config.yml b/.github/codeql/codeql-config.yml index d30ad51c7999b6..f5d33545c1e19f 100644 --- a/.github/codeql/codeql-config.yml +++ b/.github/codeql/codeql-config.yml @@ -2,5 +2,21 @@ paths-ignore: - benchmark - sample - spec/ruby/command_line/fixtures + - spec/ruby/core/enumerable/shared/inject.rb - spec/ruby/core/exception/fixtures + - spec/ruby/core/proc/parameters_spec.rb + - spec/ruby/core/proc/ruby2_keywords_spec.rb + - spec/ruby/core/range/reverse_each_spec.rb - spec/ruby/language/fixtures + - spec/ruby/language/lambda_spec.rb + - spec/ruby/language/method_spec.rb + - spec/ruby/language/string_spec.rb + - test/error_highlight/test_error_highlight.rb + - test/prism/result/named_capture_test.rb + - test/ruby/test_call.rb + - test/ruby/test_signal.rb + - test/ruby/test_super.rb + - test/ruby/test_syntax.rb + - test/ruby/test_unicode_escape.rb + - test/rubygems/specifications/foo-0.0.1-x86-mswin32.gemspec + - trace_point.rb