[llvm] ce80c80 - [Hashing] Use a non-deterministic seed if LLVM_ENABLE_ABI_BREAKING_CHECKS

via llvm-commits llvm-commits at lists.llvm.org
Fri Jun 28 15:30:23 PDT 2024


Author: Fangrui Song
Date: 2024-06-28T15:30:19-07:00
New Revision: ce80c80dca45c7b4636a3e143973e2c6cbdb2884

URL: https://github.com/llvm/llvm-project/commit/ce80c80dca45c7b4636a3e143973e2c6cbdb2884
DIFF: https://github.com/llvm/llvm-project/commit/ce80c80dca45c7b4636a3e143973e2c6cbdb2884.diff

LOG: [Hashing] Use a non-deterministic seed if LLVM_ENABLE_ABI_BREAKING_CHECKS

Hashing.h provides hash_value/hash_combine/hash_combine_range, which are
primarily used by `DenseMap<StringRef, X>`

Users shouldn't rely on specific hash values due to size_t differences
on 32-bit/64-bit platforms and potential algorithm changes.
`set_fixed_execution_hash_seed` is provided but it has never been used.

In LLVM_ENABLE_ABI_BREAKING_CHECKS builds, take the the address of a
static storage duration variable as the seed like
absl/hash/internal/hash.h `kSeed`. (See https://reviews.llvm.org/D93931
for workaround for older Clang. Mach-O x86-64 forces PIC, so absl's
`__apple_build_version__` check is unnecessary.)

LLVM_ENABLE_ABI_BREAKING_CHECKS defaults to `WITH_ASSERTS` and is
enabled in an assertion build.

In a non-assertion build, `get_execution_seed` returns the fixed value
regardless of `NDEBUG`. Removing a variable load yields noticeable
size/performance improvement.

A few users relying on the iteration order of `DenseMap<StringRef, X>`
have been fixed (e.g., f8f4235612b9 c025bd1fdbbd 89e8e63f47ff
86eb6bf6715c eb8d03656549 0ea6b8e476c2 58d7a6e0e636 8ea31db27211
592abf29f9f7 664497557ae7).
>From my experience fixing [`StringMap`](https://discourse.llvm.org/t/reverse-iteration-bots/72224)
iteration order issues, the scale of issues is similar.

Pull Request: https://github.com/llvm/llvm-project/pull/96282

Added: 
    

Modified: 
    llvm/include/llvm/ADT/Hashing.h
    llvm/lib/Support/CMakeLists.txt
    llvm/unittests/ADT/HashingTest.cpp
    llvm/utils/gn/secondary/llvm/lib/Support/BUILD.gn

Removed: 
    llvm/lib/Support/Hashing.cpp


################################################################################
diff  --git a/llvm/include/llvm/ADT/Hashing.h b/llvm/include/llvm/ADT/Hashing.h
index a5477362a5079..177fb0318bf80 100644
--- a/llvm/include/llvm/ADT/Hashing.h
+++ b/llvm/include/llvm/ADT/Hashing.h
@@ -44,6 +44,7 @@
 #ifndef LLVM_ADT_HASHING_H
 #define LLVM_ADT_HASHING_H
 
+#include "llvm/Config/abi-breaking.h"
 #include "llvm/Support/DataTypes.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/SwapByteOrder.h"
@@ -126,23 +127,6 @@ hash_code hash_value(const std::basic_string<T> &arg);
 /// Compute a hash_code for a standard string.
 template <typename T> hash_code hash_value(const std::optional<T> &arg);
 
-/// Override the execution seed with a fixed value.
-///
-/// This hashing library uses a per-execution seed designed to change on each
-/// run with high probability in order to ensure that the hash codes are not
-/// attackable and to ensure that output which is intended to be stable does
-/// not rely on the particulars of the hash codes produced.
-///
-/// That said, there are use cases where it is important to be able to
-/// reproduce *exactly* a specific behavior. To that end, we provide a function
-/// which will forcibly set the seed to a fixed value. This must be done at the
-/// start of the program, before any hashes are computed. Also, it cannot be
-/// undone. This makes it thread-hostile and very hard to use outside of
-/// immediately on start of a simple program designed for reproducible
-/// behavior.
-void set_fixed_execution_hash_seed(uint64_t fixed_value);
-
-
 // All of the implementation details of actually computing the various hash
 // code values are held within this namespace. These routines are included in
 // the header file mainly to allow inlining and constant propagation.
@@ -322,24 +306,20 @@ struct hash_state {
   }
 };
 
-
-/// A global, fixed seed-override variable.
-///
-/// This variable can be set using the \see llvm::set_fixed_execution_seed
-/// function. See that function for details. Do not, under any circumstances,
-/// set or read this variable.
-extern uint64_t fixed_seed_override;
-
+/// In LLVM_ENABLE_ABI_BREAKING_CHECKS builds, the seed is non-deterministic
+/// (address of a variable) to prevent having users depend on the particular
+/// hash values. On platforms without ASLR, this is still likely
+/// non-deterministic per build.
 inline uint64_t get_execution_seed() {
-  // FIXME: This needs to be a per-execution seed. This is just a placeholder
-  // implementation. Switching to a per-execution seed is likely to flush out
-  // instability bugs and so will happen as its own commit.
-  //
-  // However, if there is a fixed seed override set the first time this is
-  // called, return that instead of the per-execution seed.
-  const uint64_t seed_prime = 0xff51afd7ed558ccdULL;
-  static uint64_t seed = fixed_seed_override ? fixed_seed_override : seed_prime;
-  return seed;
+  // Work around x86-64 negative offset folding for old Clang -fno-pic
+  // https://reviews.llvm.org/D93931
+#if LLVM_ENABLE_ABI_BREAKING_CHECKS &&                                         \
+    (!defined(__clang__) || __clang_major__ > 11)
+  static const char seed = 0;
+  return static_cast<uint64_t>(reinterpret_cast<uintptr_t>(&seed));
+#else
+  return 0xff51afd7ed558ccdULL;
+#endif
 }
 
 

diff  --git a/llvm/lib/Support/CMakeLists.txt b/llvm/lib/Support/CMakeLists.txt
index c87785994fec7..f653379e30334 100644
--- a/llvm/lib/Support/CMakeLists.txt
+++ b/llvm/lib/Support/CMakeLists.txt
@@ -187,7 +187,6 @@ add_llvm_component_library(LLVMSupport
   FormatVariadic.cpp
   GlobPattern.cpp
   GraphWriter.cpp
-  Hashing.cpp
   HexagonAttributeParser.cpp
   HexagonAttributes.cpp
   InitLLVM.cpp

diff  --git a/llvm/lib/Support/Hashing.cpp b/llvm/lib/Support/Hashing.cpp
deleted file mode 100644
index 1b20a670434f1..0000000000000
--- a/llvm/lib/Support/Hashing.cpp
+++ /dev/null
@@ -1,28 +0,0 @@
-//===-------------- lib/Support/Hashing.cpp -------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file provides implementation bits for the LLVM common hashing
-// infrastructure. Documentation and most of the other information is in the
-// header file.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/ADT/Hashing.h"
-
-using namespace llvm;
-
-// Provide a definition and static initializer for the fixed seed. This
-// initializer should always be zero to ensure its value can never appear to be
-// non-zero, even during dynamic initialization.
-uint64_t llvm::hashing::detail::fixed_seed_override = 0;
-
-// Implement the function for forced setting of the fixed seed.
-// FIXME: Use atomic operations here so that there is no data race.
-void llvm::set_fixed_execution_hash_seed(uint64_t fixed_value) {
-  hashing::detail::fixed_seed_override = fixed_value;
-}

diff  --git a/llvm/unittests/ADT/HashingTest.cpp b/llvm/unittests/ADT/HashingTest.cpp
index ab13ee833ce55..c28356e229e66 100644
--- a/llvm/unittests/ADT/HashingTest.cpp
+++ b/llvm/unittests/ADT/HashingTest.cpp
@@ -235,78 +235,6 @@ TEST(HashingTest, HashCombineRangeLengthDiff) {
   }
 }
 
-TEST(HashingTest, HashCombineRangeGoldenTest) {
-  struct { const char *s; uint64_t hash; } golden_data[] = {
-#if SIZE_MAX == UINT64_MAX || SIZE_MAX == UINT32_MAX
-    { "a",                                0xaeb6f9d5517c61f8ULL },
-    { "ab",                               0x7ab1edb96be496b4ULL },
-    { "abc",                              0xe38e60bf19c71a3fULL },
-    { "abcde",                            0xd24461a66de97f6eULL },
-    { "abcdefgh",                         0x4ef872ec411dec9dULL },
-    { "abcdefghijklm",                    0xe8a865539f4eadfeULL },
-    { "abcdefghijklmnopqrstu",            0x261cdf85faaf4e79ULL },
-    { "abcdefghijklmnopqrstuvwxyzabcdef", 0x43ba70e4198e3b2aULL },
-    { "abcdefghijklmnopqrstuvwxyzabcdef"
-      "abcdefghijklmnopqrstuvwxyzghijkl"
-      "abcdefghijklmnopqrstuvwxyzmnopqr"
-      "abcdefghijklmnopqrstuvwxyzstuvwx"
-      "abcdefghijklmnopqrstuvwxyzyzabcd", 0xdcd57fb2afdf72beULL },
-    { "a",                                0xaeb6f9d5517c61f8ULL },
-    { "aa",                               0xf2b3b69a9736a1ebULL },
-    { "aaa",                              0xf752eb6f07b1cafeULL },
-    { "aaaaa",                            0x812bd21e1236954cULL },
-    { "aaaaaaaa",                         0xff07a2cff08ac587ULL },
-    { "aaaaaaaaaaaaa",                    0x84ac949d54d704ecULL },
-    { "aaaaaaaaaaaaaaaaaaaaa",            0xcb2c8fb6be8f5648ULL },
-    { "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 0xcc40ab7f164091b6ULL },
-    { "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
-      "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
-      "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
-      "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
-      "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 0xc58e174c1e78ffe9ULL },
-    { "z",                                0x1ba160d7e8f8785cULL },
-    { "zz",                               0x2c5c03172f1285d7ULL },
-    { "zzz",                              0x9d2c4f4b507a2ac3ULL },
-    { "zzzzz",                            0x0f03b9031735693aULL },
-    { "zzzzzzzz",                         0xe674147c8582c08eULL },
-    { "zzzzzzzzzzzzz",                    0x3162d9fa6938db83ULL },
-    { "zzzzzzzzzzzzzzzzzzzzz",            0x37b9a549e013620cULL },
-    { "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz", 0x8921470aff885016ULL },
-    { "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"
-      "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"
-      "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"
-      "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"
-      "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz", 0xf60fdcd9beb08441ULL },
-    { "a",                                0xaeb6f9d5517c61f8ULL },
-    { "ab",                               0x7ab1edb96be496b4ULL },
-    { "aba",                              0x3edb049950884d0aULL },
-    { "ababa",                            0x8f2de9e73a97714bULL },
-    { "abababab",                         0xee14a29ddf0ce54cULL },
-    { "ababababababa",                    0x38b3ddaada2d52b4ULL },
-    { "ababababababababababa",            0xd3665364219f2b85ULL },
-    { "abababababababababababababababab", 0xa75cd6afbf1bc972ULL },
-    { "abababababababababababababababab"
-      "abababababababababababababababab"
-      "abababababababababababababababab"
-      "abababababababababababababababab"
-      "abababababababababababababababab", 0x840192d129f7a22bULL }
-#else
-#error This test only supports 64-bit and 32-bit systems.
-#endif
-  };
-  for (unsigned i = 0; i < sizeof(golden_data)/sizeof(*golden_data); ++i) {
-    StringRef str = golden_data[i].s;
-    hash_code hash = hash_combine_range(str.begin(), str.end());
-#if 0 // Enable this to generate paste-able text for the above structure.
-    std::string member_str = "\"" + str.str() + "\",";
-    fprintf(stderr, " { %-35s 0x%016llxULL },\n",
-            member_str.c_str(), static_cast<uint64_t>(hash));
-#endif
-    EXPECT_EQ(static_cast<size_t>(golden_data[i].hash),
-              static_cast<size_t>(hash));
-  }
-}
-
 TEST(HashingTest, HashCombineBasicTest) {
   // Hashing a sequence of homogenous types matches range hashing.
   const int i1 = 42, i2 = 43, i3 = 123, i4 = 999, i5 = 0, i6 = 79;

diff  --git a/llvm/utils/gn/secondary/llvm/lib/Support/BUILD.gn b/llvm/utils/gn/secondary/llvm/lib/Support/BUILD.gn
index af4a6993cbc79..d6b6b71a1e59b 100644
--- a/llvm/utils/gn/secondary/llvm/lib/Support/BUILD.gn
+++ b/llvm/utils/gn/secondary/llvm/lib/Support/BUILD.gn
@@ -90,7 +90,6 @@ static_library("Support") {
     "FormattedStream.cpp",
     "GlobPattern.cpp",
     "GraphWriter.cpp",
-    "Hashing.cpp",
     "HexagonAttributeParser.cpp",
     "HexagonAttributes.cpp",
     "InitLLVM.cpp",


        


More information about the llvm-commits mailing list