[cfe-commits] RFC - Fix std::hash bugs and remove reinterpret_cast<>

Dave Zarzycki zarzycki at apple.com
Fri Dec 2 13:00:09 PST 2011


This fixes a bug where garbage is being read during std::hash of float on 64-bit platforms.
This also removes all of the calls to reinterpret_cast<>.

Dave Z.


diff --git a/include/functional b/include/functional
index 17a36cc87ad..0300b68eae8 100644
--- a/include/functional
+++ b/include/functional
@@ -1921,11 +1921,17 @@ struct _LIBCPP_VISIBLE hash<long long>
     _LIBCPP_INLINE_VISIBILITY
     size_t operator()(long long __v) const _NOEXCEPT
     {
-        size_t __r = 0;
-        const size_t* const __p = reinterpret_cast<const size_t*>(&__v);
-        for (unsigned __i = 0; __i < sizeof(argument_type)/sizeof(size_t); ++__i)
-            __r ^= __p[__i];
-        return __r;
+        if (sizeof(long long) == sizeof(size_t))
+            return __v;
+        union {
+            long long __l;
+            struct {
+                int __a;
+                int __b;
+            } __s;
+        } __u;
+        __u.__l = __v;
+        return __u.__s.__a ^ __u.__s.__b;
     }
 };
 
@@ -1936,11 +1942,17 @@ struct _LIBCPP_VISIBLE hash<unsigned long long>
     _LIBCPP_INLINE_VISIBILITY
     size_t operator()(unsigned long long __v) const _NOEXCEPT
     {
-        size_t __r = 0;
-        const size_t* const __p = reinterpret_cast<const size_t*>(&__v);
-        for (unsigned __i = 0; __i < sizeof(argument_type)/sizeof(size_t); ++__i)
-            __r ^= __p[__i];
-        return __r;
+        if (sizeof(unsigned long long) == sizeof(size_t))
+            return __v;
+        union {
+            unsigned long long __l;
+            struct {
+                int __a;
+                int __b;
+            } __s;
+        } __u;
+        __u.__l = __v;
+        return __u.__s.__a ^ __u.__s.__b;
     }
 };
 
@@ -1953,8 +1965,12 @@ struct _LIBCPP_VISIBLE hash<float>
     {
         if (__v == 0)
             return 0;
-        const size_t* const __p = reinterpret_cast<const size_t*>(&__v);
-        return *__p;
+        union {
+            unsigned int __d;
+            float __f;
+        } __u;
+        __u.__f = __v;
+        return __u.__d;
     }
 };
 
@@ -1967,11 +1983,21 @@ struct _LIBCPP_VISIBLE hash<double>
     {
         if (__v == 0)
             return 0;
-        size_t __r = 0;
-        const size_t* const __p = reinterpret_cast<const size_t*>(&__v);
-        for (unsigned __i = 0; __i < sizeof(argument_type)/sizeof(size_t); ++__i)
-            __r ^= __p[__i];
-        return __r;
+        if (sizeof(double) == sizeof(size_t)) {
+            union {
+                double __f;
+                size_t __d;
+            } __u;
+            __u.__f = __v;
+            return __u.__d;
+        } else {
+            union {
+                float __f;
+                size_t __d;
+            } __u;
+            __u.__f = __v;
+            return __u.__d;
+        }
     }
 };
 
@@ -1984,11 +2010,21 @@ struct _LIBCPP_VISIBLE hash<long double>
     {
         if (__v == 0)
             return 0;
-        size_t __r = 0;
-        const size_t* const __p = reinterpret_cast<const size_t*>(&__v);
-        for (unsigned __i = 0; __i < sizeof(argument_type)/sizeof(size_t); ++__i)
-            __r ^= __p[__i];
-        return __r;
+        if (sizeof(double) == sizeof(size_t)) {
+            union {
+                double __f;
+                size_t __d;
+            } __u;
+            __u.__f = __v;
+            return __u.__d;
+        } else {
+            union {
+                float __f;
+                size_t __d;
+            } __u;
+            __u.__f = __v;
+            return __u.__d;
+        }
     }
 };
 
-- 
1.7.8.rc4




More information about the cfe-commits mailing list