Skip to content

Commit ed6fb35

Browse files
authored
Fix possible collision in hash function (#1585)
Signed-off-by: Michael Mior <mmior@mail.rit.edu>
1 parent 64063dc commit ed6fb35

File tree

2 files changed

+30
-5
lines changed

2 files changed

+30
-5
lines changed

src/core/json/include/sourcemeta/core/json_hash.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,10 +126,11 @@ template <typename T> struct PropertyHashJSON {
126126
// This case is specifically designed to be constant with regards to
127127
// string length, and to exploit the fact that most JSON objects don't
128128
// have a lot of entries, so hash collision is not as common
129-
return {(size + static_cast<typename hash_type::type>(value.front()) +
129+
return {1 +
130+
(size + static_cast<typename hash_type::type>(value.front()) +
130131
static_cast<typename hash_type::type>(value.back())) %
131-
// Make sure the property hash can never exceed 8 bits
132-
256};
132+
// Make sure the property hash can never exceed 8 bits
133+
255};
133134
}
134135
}
135136

test/json/json_hash_test.cc

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -619,12 +619,36 @@ TEST(JSON_key_hash, hash_fooooooooooooooooooooooooooooooo) {
619619
EXPECT_FALSE(hasher.is_perfect(hash));
620620
#if defined(__SIZEOF_INT128__)
621621
EXPECT_EQ(hash.a,
622-
(__uint128_t{0x0000000000000000} << 64) | 0x00000000000000f5);
622+
(__uint128_t{0x0000000000000000} << 64) | 0x00000000000000f6);
623623
EXPECT_EQ(hash.b,
624624
(__uint128_t{0x0000000000000000} << 64) | 0x0000000000000000);
625625
#else
626626
// 0x20 (length) + 0x66 (f) + 0x6f (o)
627-
EXPECT_EQ(hash.a, 0x00000000000000f5);
627+
EXPECT_EQ(hash.a, 0x00000000000000f6);
628+
EXPECT_EQ(hash.b, 0x0000000000000000);
629+
EXPECT_EQ(hash.c, 0x0000000000000000);
630+
EXPECT_EQ(hash.d, 0x0000000000000000);
631+
#endif
632+
}
633+
634+
TEST(JSON_key_hash, hash_no_collision) {
635+
const sourcemeta::core::PropertyHashJSON<sourcemeta::core::JSON::String>
636+
hasher;
637+
const sourcemeta::core::JSON::String value{
638+
"zaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
639+
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
640+
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
641+
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaz"};
642+
const auto hash{hasher(value)};
643+
EXPECT_FALSE(hasher.is_perfect(hash));
644+
#if defined(__SIZEOF_INT128__)
645+
EXPECT_EQ(hash.a,
646+
(__uint128_t{0x0000000000000000} << 64) | 0x0000000000000003);
647+
EXPECT_EQ(hash.b,
648+
(__uint128_t{0x0000000000000000} << 64) | 0x0000000000000000);
649+
#else
650+
// 0x10C (length) + 0x7A (z) + 0x7A (z)
651+
EXPECT_EQ(hash.a, 0x0000000000000003);
628652
EXPECT_EQ(hash.b, 0x0000000000000000);
629653
EXPECT_EQ(hash.c, 0x0000000000000000);
630654
EXPECT_EQ(hash.d, 0x0000000000000000);

0 commit comments

Comments
 (0)