QHash: Initialize the hash seed as soon as QtCore loads
Instead of lazily initializing (with some platform exceptions, see the equivalent qsimd.cpp commit). The rationale is the same as for qCpuFeatures(): this the qHashBits() function is hot and the current code generation needs to save a lot of state because of the possible call to the C++ runtime functions to enable the thread-safe initialization of the hash seed. [ChangeLog][Important Behavior Changes] QtCore now initializes the QHash global seed before the main() function is run, so it is no longer possible to use qputenv() to affect the seed value for the current process. Disabling the random global seed for the current process should be done programmatically with by calling either the 6.2 function QHashSeed::setDeterministicGlobalSeed() or, if compatibility with Qt 5 is required, by calling qSetGlobalQHashSeed() with value 0. Change-Id: I54f205f6b7314351b078fffd16cf7eae93f9e27e Reviewed-by: Lars Knoll <lars.knoll@qt.io>
This commit is contained in:
parent
41b2c4204b
commit
cc5cc3225d
@ -35,8 +35,10 @@ qt_internal_add_module(Core
|
||||
NO_GENERATE_METATYPES # metatypes are extracted manually below
|
||||
EXCEPTIONS
|
||||
SOURCES
|
||||
# Keep qsimd.cpp first so its global static runs first
|
||||
# Keep these .cpp files in the first and in the order they are so their
|
||||
# static initialization order is retained
|
||||
global/qsimd.cpp global/qsimd.h global/qsimd_p.h
|
||||
tools/qhash.cpp tools/qhash.h
|
||||
|
||||
# Keep the rest alphabetical
|
||||
compat/removed_api.cpp
|
||||
@ -226,7 +228,6 @@ qt_internal_add_module(Core
|
||||
tools/qduplicatetracker_p.h
|
||||
tools/qflatmap_p.h
|
||||
tools/qfreelist.cpp tools/qfreelist_p.h
|
||||
tools/qhash.cpp tools/qhash.h
|
||||
tools/qhashfunctions.h
|
||||
tools/qiterator.h
|
||||
tools/qline.cpp tools/qline.h
|
||||
|
@ -66,11 +66,17 @@
|
||||
#ifndef QT_BOOTSTRAPPED
|
||||
#include <qcoreapplication.h>
|
||||
#include <qrandom.h>
|
||||
#include <private/qlocale_tools_p.h>
|
||||
#endif // QT_BOOTSTRAPPED
|
||||
|
||||
#include <array>
|
||||
#include <limits.h>
|
||||
|
||||
#if defined(QT_NO_DEBUG) && !defined(NDEBUG)
|
||||
# define NDEBUG
|
||||
#endif
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef Q_CC_GNU
|
||||
# define Q_DECL_HOT_FUNCTION __attribute__((hot))
|
||||
#else
|
||||
@ -89,7 +95,11 @@ struct HashSeedStorage
|
||||
static constexpr int SeedCount = 2;
|
||||
QBasicAtomicInteger<quintptr> seeds[SeedCount] = { Q_BASIC_ATOMIC_INITIALIZER(0), Q_BASIC_ATOMIC_INITIALIZER(0) };
|
||||
|
||||
#if !QT_SUPPORTS_INIT_PRIORITY || defined(QT_BOOTSTRAPPED)
|
||||
constexpr HashSeedStorage() = default;
|
||||
#else
|
||||
HashSeedStorage() { initialize(0); }
|
||||
#endif
|
||||
|
||||
enum State {
|
||||
OverriddenByEnvironment = -1,
|
||||
@ -126,19 +136,24 @@ struct HashSeedStorage
|
||||
|
||||
private:
|
||||
Q_DECL_COLD_FUNCTION Q_NEVER_INLINE StateResult initialize(int which) noexcept;
|
||||
[[maybe_unused]] static void ensureConstexprConstructibility()
|
||||
{
|
||||
static_assert(std::is_trivially_destructible_v<HashSeedStorage>);
|
||||
static constexpr HashSeedStorage dummy {};
|
||||
Q_UNUSED(dummy);
|
||||
}
|
||||
};
|
||||
|
||||
[[maybe_unused]] HashSeedStorage::StateResult HashSeedStorage::initialize(int which) noexcept
|
||||
{
|
||||
StateResult result = { 0, OverriddenByEnvironment };
|
||||
bool ok;
|
||||
int seed = qEnvironmentVariableIntValue("QT_HASH_SEED", &ok);
|
||||
#ifdef QT_BOOTSTRAPPED
|
||||
Q_UNUSED(which);
|
||||
Q_UNREACHABLE();
|
||||
#else
|
||||
// can't use qEnvironmentVariableIntValue (reentrancy)
|
||||
const char *seedstr = getenv("QT_HASH_SEED");
|
||||
const char *endptr = nullptr;
|
||||
bool ok = false;
|
||||
int seed;
|
||||
if (seedstr)
|
||||
seed = qstrntoll(seedstr, strlen(seedstr), &endptr, 10, &ok);
|
||||
if (ok && endptr != seedstr + strlen(seedstr))
|
||||
ok = false;
|
||||
if (ok) {
|
||||
if (seed) {
|
||||
// can't use qWarning here (reentrancy)
|
||||
@ -158,6 +173,7 @@ private:
|
||||
result.requestedSeed = x.data[i];
|
||||
}
|
||||
result.state = JustInitialized;
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -166,14 +182,15 @@ inline HashSeedStorage::StateResult HashSeedStorage::state(int which)
|
||||
constexpr quintptr BadSeed = quintptr(Q_UINT64_C(0x5555'5555'5555'5555));
|
||||
StateResult result = { BadSeed, AlreadyInitialized };
|
||||
|
||||
#ifndef QT_BOOTSTRAPPED
|
||||
#if defined(QT_BOOTSTRAPPED)
|
||||
result = { 0, OverriddenByEnvironment };
|
||||
#elif !QT_SUPPORTS_INIT_PRIORITY
|
||||
// dynamic initialization
|
||||
static auto once = [&]() {
|
||||
result = initialize(which);
|
||||
return true;
|
||||
}();
|
||||
Q_UNUSED(once);
|
||||
#else
|
||||
result = { 0, OverriddenByEnvironment };
|
||||
#endif
|
||||
|
||||
if (result.state == AlreadyInitialized && which >= 0)
|
||||
@ -185,6 +202,9 @@ inline HashSeedStorage::StateResult HashSeedStorage::state(int which)
|
||||
/*
|
||||
The QHash seed itself.
|
||||
*/
|
||||
#ifdef Q_DECL_INIT_PRIORITY
|
||||
Q_DECL_INIT_PRIORITY(05)
|
||||
#endif
|
||||
static HashSeedStorage qt_qhash_seed;
|
||||
|
||||
/*
|
||||
|
Loading…
x
Reference in New Issue
Block a user