Issue #22019 has been updated by shugo (Shugo Maeda). jhawthorn (John Hawthorn) wrote:
It might also be helpful to prevent the ifunc from being called after return. Some iterators (ex. `sort_by`) will raise a runtime error when this happens, but it's done ad-hoc (and detection depends on the variable still being accessible).
I've created a pull request for a comprehensive fix: https://github.com/ruby/ruby/pull/17777 When `rb_iterate0()` returns, and the ifunc's `data` points into the machine stack of the current execution context, `ifunc->func` is replaced with a stub that raises a `RuntimeError`: ``` $ ./tool/runruby.rb t.rb t.rb:10:in '<main>': iterator block was called after iteration ended (RuntimeError) ``` The only user-visible change is that invoking a captured block after the iterating method has returned now raises a `RuntimeError` instead of crashing. This is consistent with the existing `"sort_by reentered"` guard; the existing callcc-based "reentered" tests pass unchanged. ---------------------------------------- Bug #22019: Set#intersect () segv if the block is called after return https://bugs.ruby-lang.org/issues/22019#change-118009 * Author: jhawthorn (John Hawthorn) * Status: Open * Assignee: jhawthorn (John Hawthorn) * Backport: 3.3: UNKNOWN, 3.4: UNKNOWN, 4.0: UNKNOWN ---------------------------------------- ```ruby class C include Enumerable def each(&b) $b = b yield 1 end end Set[1, 2, 3] & C.new $b.call(1) # [BUG] Segmentation fault at 0x00007f21bfa67f60 ``` The cause is essentially the same as #5801, we're initializing an ifunc pointing to a stack-allocated struct. The solution I think is to only ever use `rb_block_call` with a GC managed object like an imemo_memo. In addition to `set_intersection_block` this likely also affects, `lazy_flat_map_i`, `nmin_i`, `enum_sum_i`, and `product_each_i` all of which are passed a stack buffer. It might also be helpful to prevent the ifunc from being called after return. Some iterators (ex. `sort_by`) will raise a runtime error when this happens, but it's done ad-hoc (and detection depends on the variable still being accessible). -- https://bugs.ruby-lang.org/