diff --git a/libcxx/include/__config b/libcxx/include/__config --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -134,6 +134,15 @@ # define _LIBCPP_ABI_DO_NOT_EXPORT_VECTOR_BASE_COMMON // According to the Standard, `bitset::operator[] const` returns bool # define _LIBCPP_ABI_BITSET_VECTOR_BOOL_CONST_SUBSCRIPT_RETURN_BOOL +// Fix the implementation of CityHash used for std::hash. +// This is an ABI break because `std::hash` will return a different result, +// which means that hashing the same object in translation units built against +// different versions of libc++ can return inconsistent results. This is especially +// tricky since std::hash is used in the implementation of unordered containers. +// +// The incorrect implementation of CityHash has the problem that it drops some +// bits on the floor. +# define _LIBCPP_ABI_FIX_CITYHASH_IMPLEMENTATION // Remove the base 10 implementation of std::to_chars from the dylib. // The implementation moved to the header, but we still export the symbols from // the dylib for backwards compatibility. diff --git a/libcxx/include/__functional/hash.h b/libcxx/include/__functional/hash.h --- a/libcxx/include/__functional/hash.h +++ b/libcxx/include/__functional/hash.h @@ -140,7 +140,11 @@ if (__len >= 4) { const uint32_t __a = std::__loadword(__s); const uint32_t __b = std::__loadword(__s + __len - 4); +#ifdef _LIBCPP_ABI_FIX_CITYHASH_IMPLEMENTATION return __hash_len_16(__len + (static_cast<_Size>(__a) << 3), __b); +#else + return __hash_len_16(__len + (__a << 3), __b); +#endif } if (__len > 0) { const unsigned char __a = static_cast(__s[0]); diff --git a/libcxx/test/libcxx/utilities/utility/__murmur2_or_cityhash.pass.cpp b/libcxx/test/libcxx/utilities/utility/__murmur2_or_cityhash.pass.cpp --- a/libcxx/test/libcxx/utilities/utility/__murmur2_or_cityhash.pass.cpp +++ b/libcxx/test/libcxx/utilities/utility/__murmur2_or_cityhash.pass.cpp @@ -10,6 +10,10 @@ // UNSUPPORTED: c++03 +// In ABI v1, our CityHash implementation is incorrect and fixing it would +// be an ABI break. +// REQUIRES: libcpp-abi-version=2 + #include #include #include