summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNobuyoshi Nakada <[email protected]>2020-12-31 08:39:20 +0900
committerNARUSE, Yui <[email protected]>2021-01-13 17:06:48 +0900
commitb2beb8586e930c168af434d6545f75d76123192b (patch)
treec54431383807c40fe0f51ced3dfd7c227092481e
parentb93e16dc0f45069d4a5fcce20d5c4437e151f0a8 (diff)
Make any hash values fixable [Bug #17488]
As hnum is an unsigned st_index_t, the result of RSHIFT may not be in the fixable range. Co-authored-by: NeoCat <[email protected]>
-rw-r--r--hash.c11
-rw-r--r--test/ruby/test_hash.rb26
2 files changed, 29 insertions, 8 deletions
diff --git a/hash.c b/hash.c
index c3a512b8e9..0ed2692f24 100644
--- a/hash.c
+++ b/hash.c
@@ -223,15 +223,10 @@ any_hash(VALUE a, st_index_t (*other_func)(VALUE))
default:
hnum = other_func(a);
}
-#if SIZEOF_LONG < SIZEOF_ST_INDEX_T
- if (hnum > 0)
- hnum &= (unsigned long)-1 >> 2;
+ if ((SIGNED_VALUE)hnum > 0)
+ hnum &= FIXNUM_MAX;
else
- hnum |= ~((unsigned long)-1 >> 2);
-#else
- hnum <<= 1;
- hnum = RSHIFT(hnum, 1);
-#endif
+ hnum |= FIXNUM_MIN;
return (long)hnum;
}
diff --git a/test/ruby/test_hash.rb b/test/ruby/test_hash.rb
index c4b93836c6..62d8b3f836 100644
--- a/test/ruby/test_hash.rb
+++ b/test/ruby/test_hash.rb
@@ -1865,4 +1865,30 @@ class TestHash < Test::Unit::TestCase
{a: 1}.each(&->(k, v) {})
end
end
+
+ def test_any_hash_fixable
+ 20.times do
+ assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
+ begin;
+ require "delegate"
+ typename = DelegateClass(String)
+
+ hash = {
+ "Int" => true,
+ "Float" => true,
+ "String" => true,
+ "Boolean" => true,
+ "WidgetFilter" => true,
+ "WidgetAggregation" => true,
+ "WidgetEdge" => true,
+ "WidgetSortOrder" => true,
+ "WidgetGrouping" => true,
+ }
+
+ hash.each_key do |key|
+ assert_send([hash, :key?, typename.new(key)])
+ end
+ end;
+ end
+ end
end