[ruby-core:116523] [Ruby master Bug#20230] Fix crash when passing large keyword splat to method accepting keywords and keyword splat

Issue #20230 has been reported by jeremyevans0 (Jeremy Evans). ---------------------------------------- Bug #20230: Fix crash when passing large keyword splat to method accepting keywords and keyword splat https://bugs.ruby-lang.org/issues/20230 * Author: jeremyevans0 (Jeremy Evans) * Status: Open * Priority: Normal * Backport: 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN ---------------------------------------- The following code causes a crash in Ruby 2.2-3.3 and master: ```ruby h = {} 1000000.times{|i| h[i.to_s.to_sym] = i} def f(kw: 1, **kws) end f(**h) ``` Inside a thread or fiber, the size of the keyword splat could be much smaller and still cause a crash. This is similar to the issue in #4040, but for keyword splats instead of positional splats. I found this issue while optimizing method calling by reducing implicit allocations. Given the following code: ```ruby def f(kw: , **kws) end kw = {kw: 1} f(**kw) ``` The `f(**kw)` call previously allocated two hashes callee side instead of a single hash. This is because `setup_parameters_complex` would extract the keywords from the keyword splat hash to the C stack, to attempt to mirror the case when literal keywords are passed without a keyword splat. Then, `make_rest_kw_hash` would build a new hash based on the extracted keywords that weren't used for literal keywords. I have submitted a pull request which changes the implementation so that if a keyword splat is passed, literal keywords are deleted from the keyword splat hash (or a copy of the hash if the hash is not mutable): https://github.com/ruby/ruby/pull/9776 In addition to fixing the bug, the new implementation also eliminates the unnecessary hash allocation. -- https://bugs.ruby-lang.org/

Issue #20230 has been updated by jeremyevans0 (Jeremy Evans). Status changed from Open to Closed Fixed by commit:c20e819e8b04e84a4103ca9a036022543459c213 ---------------------------------------- Bug #20230: Fix crash when passing large keyword splat to method accepting keywords and keyword splat https://bugs.ruby-lang.org/issues/20230#change-106726 * Author: jeremyevans0 (Jeremy Evans) * Status: Closed * Priority: Normal * Backport: 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN ---------------------------------------- The following code causes a crash in Ruby 2.2-3.3 and master: ```ruby h = {} 1000000.times{|i| h[i.to_s.to_sym] = i} def f(kw: 1, **kws) end f(**h) ``` Inside a thread or fiber, the size of the keyword splat could be much smaller and still cause a crash. This is similar to the issue in #4040, but for keyword splats instead of positional splats. I found this issue while optimizing method calling by reducing implicit allocations. Given the following code: ```ruby def f(kw: , **kws) end kw = {kw: 1} f(**kw) ``` The `f(**kw)` call previously allocated two hashes callee side instead of a single hash. This is because `setup_parameters_complex` would extract the keywords from the keyword splat hash to the C stack, to attempt to mirror the case when literal keywords are passed without a keyword splat. Then, `make_rest_kw_hash` would build a new hash based on the extracted keywords that weren't used for literal keywords. I have submitted a pull request which changes the implementation so that if a keyword splat is passed, literal keywords are deleted from the keyword splat hash (or a copy of the hash if the hash is not mutable): https://github.com/ruby/ruby/pull/9776 In addition to fixing the bug, the new implementation also eliminates the unnecessary hash allocation. -- https://bugs.ruby-lang.org/
participants (1)
-
jeremyevans0 (Jeremy Evans)