diff --git a/test/ruby/test_keyword.rb b/test/ruby/test_keyword.rb index 576f219dac295d..cfc3dc11da511f 100644 --- a/test/ruby/test_keyword.rb +++ b/test/ruby/test_keyword.rb @@ -4273,6 +4273,31 @@ def test_many_kwargs assert_equal(:ok, many_kwargs(e0: :ok)[i], "#{i}: e0"); i+=1 end + def test_many_kwargs_with_integer_refinement + assert_separately([], <<~'RUBY') + module Ref + refine Integer do + def ==(other) super; end + end + end + + # 257 indices guarantee a collision in the 8-bit hint of a small Hash. + # Keep both indices above the keyword bitmask limit. + indices = (32...289).to_a + a, b = indices.combination(2).find { |x, y| (x.hash & 0xff) == (y.hash & 0xff) } + expected = (0...289).to_a + expected[a] = {} + expected[b] = {} + params = expected.each_with_index.map { |value, i| "k#{i}: #{value.inspect}" } + eval "def victim(#{params.join(', ')}) [#{expected.each_index.map { |i| "k#{i}" }.join(', ')}]; end" + + assert_equal(expected, victim, '[Bug #22335]') + assert_equal(expected, victim(k0: 0), '[Bug #22335]') + kwargs = {k0: 0} + assert_equal(expected, victim(**kwargs), '[Bug #22335]') + RUBY + end + def test_splat_empty_hash_with_block_passing assert_valid_syntax("bug15087(**{}, &nil)") end diff --git a/vm_args.c b/vm_args.c index 2610d99c229b5e..33a41c6445737c 100644 --- a/vm_args.c +++ b/vm_args.c @@ -320,6 +320,37 @@ args_setup_kw_parameters_lookup(const ID key, VALUE *ptr, const VALUE *const pas return FALSE; } +static inline void +args_setup_kw_parameters_not_found(const VALUE *default_values, VALUE *locals, int i, int di, + int *unspecified_bits, VALUE *unspecified_bits_value) +{ + if (UNDEF_P(default_values[di])) { + locals[i] = Qnil; + + if (LIKELY(i < VM_KW_SPECIFIED_BITS_MAX)) { + *unspecified_bits |= 0x01 << di; + } + else { + VALUE bits_value = *unspecified_bits_value; + if (NIL_P(bits_value)) { + /* fixnum -> hash */ + int bits = *unspecified_bits; + *unspecified_bits_value = bits_value = rb_ident_hash_new(); + + for (int j=0; j hash */ - int j; - unspecified_bits_value = rb_hash_new(); - - for (j=0; j hash */ - int j; - unspecified_bits_value = rb_hash_new(); - - for (j=0; j