Issue #22113 has been updated by ko1 (Koichi Sasada). This ticket is from Claude code (Opus 4.8 with 1M context) :) ---------------------------------------- Bug #22113: Proc#curry produces a corrupted (false) argument under GC compaction https://bugs.ruby-lang.org/issues/22113#change-117659 * Author: ko1 (Koichi Sasada) * Status: Open * Backport: 3.3: UNKNOWN, 3.4: UNKNOWN, 4.0: UNKNOWN ---------------------------------------- ## `Proc#curry` produces a corrupted (`false`) argument under GC compaction ### Summary The `Proc#curry` rubyspec example *"combines arguments and calculates incoming arity accurately for successively currying"* (`spec/ruby/core/proc/curry_spec.rb:84`) intermittently fails with: ``` TypeError: false can't be coerced into Integer ``` One of the curried arguments — which should be an `Integer` — is read back as `false` (`Qfalse == 0`), indicating a stale/uninitialized object reference. The trigger is **GC compaction**. ### Environment ``` ruby 4.1.0dev (2026-06-14T05:19:50Z master a6e302509b) +PRISM [x86_64-linux] configured with --enable-shared ``` Observed on CI <https://ci.rvm.jp/results/trunk@ruby-sp3/6377957>, where the full rubyspec suite was run in parallel: ``` make yes-test-rubyspec MSPECOPT='--error-output stderr -j' TESTS='-j20' ``` ### Reproduction Reliably reproduces by enabling compaction alone: ```ruby # => TypeError: false can't be coerced into Integer GC.auto_compact = true l = -> a, b, c { a + b + c } loop do l1 = l.curry.call(1) raise "unexpected" unless l1.curry.call(2, 3) == 6 end ``` ``` $ ruby repro.rb repro.rb:7:in 'Integer#+': false can't be coerced into Integer (TypeError) ``` ### Observations - **`GC.auto_compact = true` alone** → `TypeError: false can't be coerced into Integer` (matches the spec failure exactly). - **`GC.stress = true` alone** (no compaction) → does **not** reproduce. - **No GC tuning**, millions of iterations → does **not** reproduce. - **`GC.stress = true` + `GC.auto_compact = true`** → escalates to a hard crash during marking: ``` [BUG] try to mark T_NONE object (obj: ... T_NONE, parent: ... T_ARRAY [E ] len: 1 (embed)) ``` Backtrace points into the curry path: ``` gc_mark_check_t_none gc/default/default.c:4800 ... rb_ary_plus array.c:5197 curry proc.c:3867 ``` This points to a reference that is not correctly updated (or not pinned) during compaction somewhere in the `Proc#curry` path (`curry()` / `make_curry_proc()` / the `rb_ary_plus` + `rb_ary_new4` accumulation of `passed`), leaving a dangling reference that reads back as `Qfalse`. ### Note on the CI run The CI run did **not** explicitly enable compaction (only `RUBY_DEBUG=ci` was set), so the exact in-the-wild trigger is not yet confirmed — possibly another GC-related spec in the same parallel worker induced a compaction. The symptom is identical and is **deterministically reproducible under `GC.auto_compact = true`**. -- https://bugs.ruby-lang.org/