murmurhash: Fix an undefined behavior when hashing function names
authorYilong Li <liyl@google.com>
Thu, 13 Jan 2022 05:52:21 +0000 (21:52 -0800)
committerCharles Giessen <46324611+charles-lunarg@users.noreply.github.com>
Thu, 13 Jan 2022 19:53:21 +0000 (12:53 -0700)
In Vulkan loader GetProcAddr handlers, for functions that are
not specified in the Vulkan registry, the loader will try loading
the name from ICDs or layers, and store the function entry into
a hashtable. The hashtable uses |murmurhash()| function to hash
Vulkan function names.

murmurhash handles data as 4-byte chunks and read one chunk at a
time; and it simply converts uint8_t pointers to uint32_t pointers
while loading data. However, the address of function name might
not be 32-bit aligned and this will cause an undefined behavior in
C99 / C11.

This change fixes the murmurhash() behavior so that it handles
unaligned access correctly. For most common platforms that supports
unaligned memory access this could compile into a single mov/load
instruction even if compiling using -O0.

Change-Id: I16011720198a0ee96e556855858a9909f95ec376

loader/murmurhash.c

index e3a372e66c014cd1674911c861b6c925bfc001cb..5b56a022e83705615dcbc17cd8cd08a5b6d829d7 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "murmurhash.h"
 
+#include <memory.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -43,20 +44,20 @@ uint32_t murmurhash(const char *key, size_t len, uint32_t seed) {
     uint32_t h = 0;
     uint32_t k = 0;
     uint8_t *d = (uint8_t *)key;  // 32 bit extract from `key'
-    const uint32_t *chunks = NULL;
+    const uint8_t *chunks = NULL;
     const uint8_t *tail = NULL;  // tail - last 8 bytes
     int i = 0;
     int l = (int)len / 4;  // chunk length
 
     h = seed;
 
-    chunks = (const uint32_t *)(d + l * 4);  // body
+    chunks = (const uint8_t *)(d + l * 4);   // body
     tail = (const uint8_t *)(d + l * 4);     // last 8 byte chunk of `key'
 
     // for each 4 byte chunk of `key'
     for (i = -l; i != 0; ++i) {
         // next 4 byte chunk of `key'
-        k = chunks[i];
+        memcpy(&k, chunks + i * 4, sizeof(k));
 
         // encode next 4 byte chunk of `key'
         k *= c1;