]> git.kaiwu.me - njs.git/commitdiff
Avoid undefined shifts in MurmurHash2
authorDmitry Volyntsev <xeioex@nginx.com>
Thu, 17 Sep 2026 21:51:00 +0000 (14:51 -0700)
committerDmitry Volyntsev <xeioexception@gmail.com>
Fri, 18 Sep 2026 20:42:16 +0000 (13:42 -0700)
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.

src/njs_murmur_hash.c

index f5ee00796c7ffe6da86b17810ada78fc144338c8..5256ff80b665bcdabddd336c41d266a92d1a10ac 100644 (file)
@@ -19,10 +19,10 @@ njs_murmur_hash2(const void *data, size_t len)
     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;
@@ -37,10 +37,10 @@ njs_murmur_hash2(const void *data, size_t len)
 
     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];
@@ -66,10 +66,10 @@ njs_murmur_hash2_uint32(const void *data)
 
     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;