Previously, input bytes were promoted to signed int before being shifted
into a hash word. A byte with its high bit set could make the 24-bit
shift undefined.
The fix is to cast input bytes to uint32_t before shifting. This
preserves the hash result and avoids undefined behavior under UBSan.
h = 0 ^ (uint32_t) len;
while (len >= 4) {
- k = p[0];
- k |= p[1] << 8;
- k |= p[2] << 16;
- k |= p[3] << 24;
+ k = (uint32_t) p[0];
+ k |= (uint32_t) p[1] << 8;
+ k |= (uint32_t) p[2] << 16;
+ k |= (uint32_t) p[3] << 24;
k *= m;
k ^= k >> 24;
switch (len) {
case 3:
- h ^= p[2] << 16;
+ h ^= (uint32_t) p[2] << 16;
/* Fall through. */
case 2:
- h ^= p[1] << 8;
+ h ^= (uint32_t) p[1] << 8;
/* Fall through. */
case 1:
h ^= p[0];
p = data;
- k = p[0];
- k |= p[1] << 8;
- k |= p[2] << 16;
- k |= p[3] << 24;
+ k = (uint32_t) p[0];
+ k |= (uint32_t) p[1] << 8;
+ k |= (uint32_t) p[2] << 16;
+ k |= (uint32_t) p[3] << 24;
k *= m;
k ^= k >> 24;