[libcxx] r294391 - Prevent UBSAN from generating unsigned overflow diagnostics in the hashing internals

Eric Fiselier via cfe-commits cfe-commits at lists.llvm.org
Tue Feb 7 16:10:10 PST 2017


Author: ericwf
Date: Tue Feb  7 18:10:10 2017
New Revision: 294391

URL: http://llvm.org/viewvc/llvm-project?rev=294391&view=rev
Log:
Prevent UBSAN from generating unsigned overflow diagnostics in the hashing internals

Added:
    libcxx/trunk/test/libcxx/utilities/function.objects/unord.hash/
    libcxx/trunk/test/libcxx/utilities/function.objects/unord.hash/murmur2_or_cityhash_ubsan_unsigned_overflow_ignored.pass.cpp
Modified:
    libcxx/trunk/include/utility
    libcxx/trunk/test/support/test_macros.h

Modified: libcxx/trunk/include/utility
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?rev=294391&r1=294390&r2=294391&view=diff
==============================================================================
--- libcxx/trunk/include/utility (original)
+++ libcxx/trunk/include/utility Tue Feb  7 18:10:10 2017
@@ -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>::operat
 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) {

Added: libcxx/trunk/test/libcxx/utilities/function.objects/unord.hash/murmur2_or_cityhash_ubsan_unsigned_overflow_ignored.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/libcxx/utilities/function.objects/unord.hash/murmur2_or_cityhash_ubsan_unsigned_overflow_ignored.pass.cpp?rev=294391&view=auto
==============================================================================
--- libcxx/trunk/test/libcxx/utilities/function.objects/unord.hash/murmur2_or_cityhash_ubsan_unsigned_overflow_ignored.pass.cpp (added)
+++ libcxx/trunk/test/libcxx/utilities/function.objects/unord.hash/murmur2_or_cityhash_ubsan_unsigned_overflow_ignored.pass.cpp Tue Feb  7 18:10:10 2017
@@ -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());
+}

Modified: libcxx/trunk/test/support/test_macros.h
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/support/test_macros.h?rev=294391&r1=294390&r2=294391&view=diff
==============================================================================
--- libcxx/trunk/test/support/test_macros.h (original)
+++ libcxx/trunk/test/support/test_macros.h Tue Feb  7 18:10:10 2017
@@ -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




More information about the cfe-commits mailing list