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

John McCall rjmccall at apple.com
Fri Dec 2 14:26:01 PST 2011


On Dec 2, 2011, at 1:00 PM, Dave Zarzycki wrote:

> 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;

<= should be fine.  Also, if you use an explicit cast to unsigned long long, you'll
suppress a warning;  it will also avoid a sign-extend in the unlikely case of
long long being smaller than size_t.

> +        union {
> +            long long __l;
> +            struct {
> +                int __a;
> +                int __b;
> +            } __s;
> +        } __u;
> +        __u.__l = __v;
> +        return __u.__s.__a ^ __u.__s.__b;

I understand that true C portability is hard, but I'm sure we can do better than this.

> @@ -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;

I'm not sure that sizeof(double) != sizeof(size_t) implies that
sizeof(float) == sizeof(size_t). :)

John.



More information about the cfe-commits mailing list