diff options
author | Lars Knoll <lars.knoll@qt.io> | 2018-04-23 21:08:10 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@qt.io> | 2018-04-25 18:50:06 +0000 |
commit | a9fc91466c2c143bea422d98af24755f43c2b97b (patch) | |
tree | 712f7da349b0949a35dbbe4217df5c7001cc1a29 | |
parent | 960424f86b1f2c5571081c2b3a1dad6587de059f (diff) |
Protect all accesses to the global engine cache by a mutex
Otherwise, we'll end up with corrupted memory when using
QRegExp from multiple threads.
Amends bbdc1b5ccbb19405f997cd67ec53b2c4860105f7.
Change-Id: I9d35897629d0bc26503aa0c537c5f99013921fdd
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
-rw-r--r-- | src/corelib/tools/qregexp.cpp | 66 |
1 files changed, 32 insertions, 34 deletions
diff --git a/src/corelib/tools/qregexp.cpp b/src/corelib/tools/qregexp.cpp index 43e31ddb8e..87b30c952e 100644 --- a/src/corelib/tools/qregexp.cpp +++ b/src/corelib/tools/qregexp.cpp @@ -3813,60 +3813,57 @@ struct QRegExpPrivate }; #if !defined(QT_NO_REGEXP_OPTIM) -typedef QHash<QRegExpEngineKey, QRegExpEngine *> EngineCache; -Q_GLOBAL_STATIC(EngineCache, globalEngineCache) -typedef QCache<QRegExpEngineKey, QRegExpEngine> UnusedEngineCache; -Q_GLOBAL_STATIC(UnusedEngineCache, globalUnusedEngineCache) -static QBasicMutex globalEngineCacheMutex; +struct QRECache +{ + typedef QHash<QRegExpEngineKey, QRegExpEngine *> EngineCache; + typedef QCache<QRegExpEngineKey, QRegExpEngine> UnusedEngineCache; + EngineCache usedEngines; + UnusedEngineCache unusedEngines; +}; +Q_GLOBAL_STATIC(QRECache, engineCache) +static QBasicMutex engineCacheMutex; #endif // QT_NO_REGEXP_OPTIM static void derefEngine(QRegExpEngine *eng, const QRegExpEngineKey &key) { - if (!eng->ref.deref()) { #if !defined(QT_NO_REGEXP_OPTIM) - if (globalUnusedEngineCache()) { - QMutexLocker locker(&globalEngineCacheMutex); - QT_TRY { - globalUnusedEngineCache()->insert(key, eng, 4 + key.pattern.length() / 4); - } QT_CATCH(const std::bad_alloc &) { - // in case of an exception (e.g. oom), just delete the engine - delete eng; - } - if (globalEngineCache()) - globalEngineCache()->remove(key); + QMutexLocker locker(&engineCacheMutex); + if (!eng->ref.deref()) { + if (QRECache *c = engineCache()) { + c->unusedEngines.insert(key, eng, 4 + key.pattern.length() / 4); + c->usedEngines.remove(key); } else { delete eng; } + } #else - Q_UNUSED(key); + Q_UNUSED(key); + if (!eng->ref.deref()) delete eng; #endif - } } static void prepareEngine_helper(QRegExpPrivate *priv) { - bool initMatchState = !priv->eng; + Q_ASSERT(!priv->eng); + #if !defined(QT_NO_REGEXP_OPTIM) - if (!priv->eng && globalUnusedEngineCache()) { - QMutexLocker locker(&globalEngineCacheMutex); - priv->eng = globalUnusedEngineCache()->take(priv->engineKey); - if (!priv->eng && globalEngineCache()) - priv->eng = globalEngineCache()->value(priv->engineKey); - if (priv->eng != 0) + QMutexLocker locker(&engineCacheMutex); + if (QRECache *c = engineCache()) { + priv->eng = c->unusedEngines.take(priv->engineKey); + if (!priv->eng) + priv->eng = c->usedEngines.value(priv->engineKey); + if (!priv->eng) + priv->eng = new QRegExpEngine(priv->engineKey); + else priv->eng->ref.ref(); + + c->usedEngines.insert(priv->engineKey, priv->eng); + return; } #endif // QT_NO_REGEXP_OPTIM - if (!priv->eng) - priv->eng = new QRegExpEngine(priv->engineKey); -#if !defined(QT_NO_REGEXP_OPTIM) - if (globalEngineCache()) - globalEngineCache()->insert(priv->engineKey, priv->eng); -#endif - - if (initMatchState) - priv->matchState.prepareForMatch(priv->eng); + priv->eng = new QRegExpEngine(priv->engineKey); } inline static void prepareEngine(QRegExpPrivate *priv) @@ -3874,6 +3871,7 @@ inline static void prepareEngine(QRegExpPrivate *priv) if (priv->eng) return; prepareEngine_helper(priv); + priv->matchState.prepareForMatch(priv->eng); } static void prepareEngineForMatch(QRegExpPrivate *priv, const QString &str) |