From a9fc91466c2c143bea422d98af24755f43c2b97b Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Mon, 23 Apr 2018 21:08:10 +0200 Subject: 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 --- src/corelib/tools/qregexp.cpp | 66 +++++++++++++++++++++---------------------- 1 file 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 EngineCache; -Q_GLOBAL_STATIC(EngineCache, globalEngineCache) -typedef QCache UnusedEngineCache; -Q_GLOBAL_STATIC(UnusedEngineCache, globalUnusedEngineCache) -static QBasicMutex globalEngineCacheMutex; +struct QRECache +{ + typedef QHash EngineCache; + typedef QCache 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) -- cgit v1.2.3