From 96b3b9616f5b09adaf879cf646daa45d061ee1d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Branimir=20Karad=C5=BEi=C4=87?= Date: Sat, 15 Aug 2015 15:04:41 -0700 Subject: [PATCH] Fixed MurmurHash unaligned read. --- include/bx/allocator.h | 8 ------ include/bx/bx.h | 8 ++++++ include/bx/hash.h | 58 +++++++++++++++++++++++++++++++++++++++++- include/bx/macros.h | 4 +++ 4 files changed, 69 insertions(+), 9 deletions(-) diff --git a/include/bx/allocator.h b/include/bx/allocator.h index 3892c38..8d3e88c 100644 --- a/include/bx/allocator.h +++ b/include/bx/allocator.h @@ -58,14 +58,6 @@ namespace bx return un.ptr; } - /// Check if pointer is aligned. _align must be power of two. - inline bool isPtrAligned(const void* _ptr, size_t _align = BX_CONFIG_ALLOCATOR_NATURAL_ALIGNMENT) - { - union { const void* ptr; size_t addr; } un; - un.ptr = _ptr; - return 0 == (un.addr & (_align-1) ); - } - struct BX_NO_VTABLE AllocatorI { virtual ~AllocatorI() = 0; diff --git a/include/bx/bx.h b/include/bx/bx.h index 5420647..48ba970 100644 --- a/include/bx/bx.h +++ b/include/bx/bx.h @@ -44,6 +44,14 @@ namespace bx Ty tmp = _a; _a = _b; _b = tmp; } + /// Check if pointer is aligned. _align must be power of two. + inline bool isPtrAligned(const void* _ptr, size_t _align) + { + union { const void* ptr; size_t addr; } un; + un.ptr = _ptr; + return 0 == (un.addr & (_align-1) ); + } + } // namespace bx // Annoying C++0x stuff.. diff --git a/include/bx/hash.h b/include/bx/hash.h index d41bb37..d2f1173 100644 --- a/include/bx/hash.h +++ b/include/bx/hash.h @@ -30,7 +30,19 @@ namespace bx void add(const void* _data, int _len) { - const uint8_t* data = (uint8_t*)_data; + if (BX_ENABLED(BX_PLATFORM_EMSCRIPTEN) + && BX_UNLIKELY(!isPtrAligned(_data, 4) ) ) + { + addUnaligned(_data, _len); + return; + } + + addAligned(_data, _len); + } + + void addAligned(const void* _data, int _len) + { + const uint8_t* data = (const uint8_t*)_data; m_size += _len; mixTail(data, _len); @@ -48,6 +60,27 @@ namespace bx mixTail(data, _len); } + void addUnaligned(const void* _data, int _len) + { + const uint8_t* data = (const uint8_t*)_data; + m_size += _len; + + mixTail(data, _len); + + while(_len >= 4) + { + uint32_t kk; + readUnaligned(data, kk); + + mmix(m_hash, kk); + + data += 4; + _len -= 4; + } + + mixTail(data, _len); + } + template void add(Ty _value) { @@ -67,6 +100,29 @@ namespace bx } private: + static void readUnaligned(const void* _data, uint32_t& _out) + { + const uint8_t* data = (const uint8_t*)_data; + if (BX_ENABLED(BX_CPU_ENDIAN_LITTLE) ) + { + _out = 0 + | data[0]<<24 + | data[1]<<16 + | data[2]<<8 + | data[3] + ; + } + else + { + _out = 0 + | data[0] + | data[1]<<8 + | data[2]<<16 + | data[3]<<24 + ; + } + } + void mixTail(const uint8_t*& _data, int& _len) { while( _len && ((_len<4) || m_count) ) diff --git a/include/bx/macros.h b/include/bx/macros.h index 5086b7e..607c8fe 100644 --- a/include/bx/macros.h +++ b/include/bx/macros.h @@ -53,6 +53,8 @@ # define BX_ALLOW_UNUSED __attribute__( (unused) ) # define BX_FORCE_INLINE __extension__ static __inline __attribute__( (__always_inline__) ) # define BX_FUNCTION __PRETTY_FUNCTION__ +# define BX_LIKELY(_x) __builtin_expect(!!(_x), 1) +# define BX_UNLIKELY(_x) __builtin_expect(!!(_x), 0) # define BX_NO_INLINE __attribute__( (noinline) ) # define BX_NO_RETURN __attribute__( (noreturn) ) # define BX_NO_VTABLE @@ -76,6 +78,8 @@ # define BX_ALLOW_UNUSED # define BX_FORCE_INLINE __forceinline # define BX_FUNCTION __FUNCTION__ +# define BX_LIKELY(_x) (_x) +# define BX_UNLIKELY(_x) (_x) # define BX_NO_INLINE __declspec(noinline) # define BX_NO_RETURN # define BX_NO_VTABLE __declspec(novtable)