[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