Prevent UBSAN from generating unsigned overflow diagnostics in the hashing internals

llvm-svn: 294391
This commit is contained in:
Eric Fiselier 2017-02-08 00:10:10 +00:00
parent 5a53567620
commit 4cdd915fda
3 changed files with 76 additions and 10 deletions

View File

@ -959,13 +959,14 @@ struct __murmur2_or_cityhash;
template <class _Size>
struct __murmur2_or_cityhash<_Size, 32>
{
_Size operator()(const void* __key, _Size __len);
inline _Size operator()(const void* __key, _Size __len)
_LIBCPP_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK;
};
// murmur2
template <class _Size>
_Size
__murmur2_or_cityhash<_Size, 32>::operator()(const void* __key, _Size __len) _LIBCPP_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK
__murmur2_or_cityhash<_Size, 32>::operator()(const void* __key, _Size __len)
{
const _Size __m = 0x5bd1e995;
const _Size __r = 24;
@ -999,7 +1000,7 @@ __murmur2_or_cityhash<_Size, 32>::operator()(const void* __key, _Size __len) _LI
template <class _Size>
struct __murmur2_or_cityhash<_Size, 64>
{
_Size operator()(const void* __key, _Size __len);
inline _Size operator()(const void* __key, _Size __len) _LIBCPP_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK;
private:
// Some primes between 2^63 and 2^64.
@ -1020,7 +1021,9 @@ struct __murmur2_or_cityhash<_Size, 64>
return __val ^ (__val >> 47);
}
static _Size __hash_len_16(_Size __u, _Size __v) {
static _Size __hash_len_16(_Size __u, _Size __v)
_LIBCPP_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK
{
const _Size __mul = 0x9ddfea08eb382d69ULL;
_Size __a = (__u ^ __v) * __mul;
__a ^= (__a >> 47);
@ -1030,7 +1033,9 @@ struct __murmur2_or_cityhash<_Size, 64>
return __b;
}
static _Size __hash_len_0_to_16(const char* __s, _Size __len) {
static _Size __hash_len_0_to_16(const char* __s, _Size __len)
_LIBCPP_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK
{
if (__len > 8) {
const _Size __a = __loadword<_Size>(__s);
const _Size __b = __loadword<_Size>(__s + __len - 8);
@ -1053,7 +1058,9 @@ struct __murmur2_or_cityhash<_Size, 64>
return __k2;
}
static _Size __hash_len_17_to_32(const char *__s, _Size __len) {
static _Size __hash_len_17_to_32(const char *__s, _Size __len)
_LIBCPP_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK
{
const _Size __a = __loadword<_Size>(__s) * __k1;
const _Size __b = __loadword<_Size>(__s + 8);
const _Size __c = __loadword<_Size>(__s + __len - 8) * __k2;
@ -1065,7 +1072,9 @@ struct __murmur2_or_cityhash<_Size, 64>
// Return a 16-byte hash for 48 bytes. Quick and dirty.
// Callers do best to use "random-looking" values for a and b.
static pair<_Size, _Size> __weak_hash_len_32_with_seeds(
_Size __w, _Size __x, _Size __y, _Size __z, _Size __a, _Size __b) {
_Size __w, _Size __x, _Size __y, _Size __z, _Size __a, _Size __b)
_LIBCPP_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK
{
__a += __w;
__b = __rotate(__b + __a + __z, 21);
const _Size __c = __a;
@ -1077,7 +1086,9 @@ struct __murmur2_or_cityhash<_Size, 64>
// Return a 16-byte hash for s[0] ... s[31], a, and b. Quick and dirty.
static pair<_Size, _Size> __weak_hash_len_32_with_seeds(
const char* __s, _Size __a, _Size __b) {
const char* __s, _Size __a, _Size __b)
_LIBCPP_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK
{
return __weak_hash_len_32_with_seeds(__loadword<_Size>(__s),
__loadword<_Size>(__s + 8),
__loadword<_Size>(__s + 16),
@ -1087,7 +1098,9 @@ struct __murmur2_or_cityhash<_Size, 64>
}
// Return an 8-byte hash for 33 to 64 bytes.
static _Size __hash_len_33_to_64(const char *__s, size_t __len) {
static _Size __hash_len_33_to_64(const char *__s, size_t __len)
_LIBCPP_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK
{
_Size __z = __loadword<_Size>(__s + 24);
_Size __a = __loadword<_Size>(__s) +
(__len + __loadword<_Size>(__s + __len - 16)) * __k0;
@ -1115,7 +1128,7 @@ struct __murmur2_or_cityhash<_Size, 64>
// cityhash64
template <class _Size>
_Size
__murmur2_or_cityhash<_Size, 64>::operator()(const void* __key, _Size __len) _LIBCPP_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK
__murmur2_or_cityhash<_Size, 64>::operator()(const void* __key, _Size __len)
{
const char* __s = static_cast<const char*>(__key);
if (__len <= 32) {

View File

@ -0,0 +1,41 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Test that UBSAN doesn't generate unsigned integer overflow diagnostics
// from within the hashing internals.
#include <utility>
#include <cstdint>
#include <limits>
#include <string>
#include "test_macros.h"
typedef std::__murmur2_or_cityhash<uint32_t> Hash32;
typedef std::__murmur2_or_cityhash<uint64_t> Hash64;
void test(const void* key, int len) {
for (int i=1; i <= len; ++i) {
Hash32 h1;
Hash64 h2;
DoNotOptimize(h1(key, i));
DoNotOptimize(h2(key, i));
}
}
int main() {
const std::string TestCases[] = {
"abcdaoeuaoeclaoeoaeuaoeuaousaotehu]+}sthoasuthaoesutahoesutaohesutaoeusaoetuhasoetuhaoseutaoseuthaoesutaohes"
"00000000000000000000000000000000000000000000000000000000000000000000000",
"1237546895+54+4554985416849484213464984765465464654564565645645646546456546546"
};
const size_t NumCases = sizeof(TestCases)/sizeof(TestCases[0]);
for (size_t i=0; i < NumCases; ++i)
test(TestCases[i].data(), TestCases[i].length());
}

View File

@ -182,6 +182,18 @@ struct is_same<T, T> { enum {value = 1}; };
#endif
#endif
#if defined(__GNUC__) || defined(__clang__)
template <class Tp>
inline void DoNotOptimize(Tp const& value) {
asm volatile("" : : "g"(value) : "memory");
}
#else
template <class Tp>
inline void DoNotOptimize(Tp const&) {
// FIXME: Do something here...
}
#endif
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif