Bug #21757
closedSplatted args array is mutated when passing unexpected kwargs
Description
The bug is very simple to provoke.
proc = ->(*) { } # we do NOT expect any keyword arguments.
args = [1, 2]
proc.(*args, bug: true)
pp args #=> [1, 2, {bug: true}]
The args array now has a third element which is exactly what got passed as keyword arguments. This is only in Ruby 3.4, 3.3 and below discard the "unexpected" keyword arguments as expected.
Updated by jeremyevans0 (Jeremy Evans) 23 days ago
- Assignee set to jeremyevans0 (Jeremy Evans)
- Backport changed from 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN to 3.2: DONTNEED, 3.3: DONTNEED, 3.4: REQUIRED
Thank you for the report. This is a bug in the allocationless anonymous splat optimization in Ruby 3.4, still present in the master branch. I'll work on a fix.
Updated by jeremyevans0 (Jeremy Evans) 23 days ago
I submitted a pull request to fix this: https://github.com/ruby/ruby/pull/15383
Updated by jeremyevans (Jeremy Evans) 16 days ago
- Status changed from Open to Closed
Applied in changeset git|6409715212d22699bd2751a363b050a5d8b94b83.
Fix allocationless anonymous splat keyword argument check
Previously, if an argument splat and keywords are provided by
the caller, it did not check whether the method/proc accepted
keywords before avoiding the allocation. This is incorrect,
because if the method/proc does not accept keywords, the
keywords passed by the caller are added as a positional
argument, so there must be an allocation to avoid mutating
the positional splat argument.
Add a check that if the caller passes keywords, the
method/proc must accept keywords in order to optimize.
If the caller passes a keyword splat, either the
method/proc must accept keywords, or the keyword splat must
be empty in order to optimize.
If keywords are explicitly disallowed via **nil, the
optimization should be skipped, because the array is mutated
before the ArgumentError exception is raised.
In addition to a test for the correct behavior, add an
allocation test for a method that accepts an anonymous splat
without keywords.
Fixes [Bug #21757]