Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions test/ruby/test_keyword.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
83 changes: 35 additions & 48 deletions vm_args.c
Original file line number Diff line number Diff line change
Expand Up @@ -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<VM_KW_SPECIFIED_BITS_MAX; j++) {
if (bits & (0x01 << j)) {
rb_hash_aset(bits_value, INT2FIX(j), Qtrue);
}
}
}
rb_hash_aset(bits_value, INT2FIX(di), Qtrue);
}
}
else {
locals[i] = default_values[di];
}
}

static void
args_setup_kw_parameters(rb_execution_context_t *const ec, const rb_iseq_t *const iseq, const rb_callable_method_entry_t *cme,
VALUE *const passed_values, const int passed_keyword_len, const VALUE *const passed_keywords,
Expand Down Expand Up @@ -352,30 +383,8 @@ args_setup_kw_parameters(rb_execution_context_t *const ec, const rb_iseq_t *cons
found++;
}
else {
if (UNDEF_P(default_values[di])) {
locals[i] = Qnil;

if (LIKELY(i < VM_KW_SPECIFIED_BITS_MAX)) {
unspecified_bits |= 0x01 << di;
}
else {
if (NIL_P(unspecified_bits_value)) {
/* fixnum -> hash */
int j;
unspecified_bits_value = rb_hash_new();

for (j=0; j<VM_KW_SPECIFIED_BITS_MAX; j++) {
if (unspecified_bits & (0x01 << j)) {
rb_hash_aset(unspecified_bits_value, INT2FIX(j), Qtrue);
}
}
}
rb_hash_aset(unspecified_bits_value, INT2FIX(di), Qtrue);
}
}
else {
locals[i] = default_values[di];
}
args_setup_kw_parameters_not_found(default_values, locals, i, di,
&unspecified_bits, &unspecified_bits_value);
}
}

Expand Down Expand Up @@ -447,30 +456,8 @@ args_setup_kw_parameters_from_kwsplat(rb_execution_context_t *const ec, const rb
locals[i] = value;
}
else {
if (UNDEF_P(default_values[di])) {
locals[i] = Qnil;

if (LIKELY(i < VM_KW_SPECIFIED_BITS_MAX)) {
unspecified_bits |= 0x01 << di;
}
else {
if (NIL_P(unspecified_bits_value)) {
/* fixnum -> hash */
int j;
unspecified_bits_value = rb_hash_new();

for (j=0; j<VM_KW_SPECIFIED_BITS_MAX; j++) {
if (unspecified_bits & (0x01 << j)) {
rb_hash_aset(unspecified_bits_value, INT2FIX(j), Qtrue);
}
}
}
rb_hash_aset(unspecified_bits_value, INT2FIX(di), Qtrue);
}
}
else {
locals[i] = default_values[di];
}
args_setup_kw_parameters_not_found(default_values, locals, i, di,
&unspecified_bits, &unspecified_bits_value);
}
}

Expand Down