[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