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>
This commit is contained in:
parent
960424f86b
commit
a9fc91466c
@ -3813,60 +3813,57 @@ struct QRegExpPrivate
|
|||||||
};
|
};
|
||||||
|
|
||||||
#if !defined(QT_NO_REGEXP_OPTIM)
|
#if !defined(QT_NO_REGEXP_OPTIM)
|
||||||
typedef QHash<QRegExpEngineKey, QRegExpEngine *> EngineCache;
|
struct QRECache
|
||||||
Q_GLOBAL_STATIC(EngineCache, globalEngineCache)
|
{
|
||||||
typedef QCache<QRegExpEngineKey, QRegExpEngine> UnusedEngineCache;
|
typedef QHash<QRegExpEngineKey, QRegExpEngine *> EngineCache;
|
||||||
Q_GLOBAL_STATIC(UnusedEngineCache, globalUnusedEngineCache)
|
typedef QCache<QRegExpEngineKey, QRegExpEngine> UnusedEngineCache;
|
||||||
static QBasicMutex globalEngineCacheMutex;
|
EngineCache usedEngines;
|
||||||
|
UnusedEngineCache unusedEngines;
|
||||||
|
};
|
||||||
|
Q_GLOBAL_STATIC(QRECache, engineCache)
|
||||||
|
static QBasicMutex engineCacheMutex;
|
||||||
#endif // QT_NO_REGEXP_OPTIM
|
#endif // QT_NO_REGEXP_OPTIM
|
||||||
|
|
||||||
static void derefEngine(QRegExpEngine *eng, const QRegExpEngineKey &key)
|
static void derefEngine(QRegExpEngine *eng, const QRegExpEngineKey &key)
|
||||||
{
|
{
|
||||||
if (!eng->ref.deref()) {
|
|
||||||
#if !defined(QT_NO_REGEXP_OPTIM)
|
#if !defined(QT_NO_REGEXP_OPTIM)
|
||||||
if (globalUnusedEngineCache()) {
|
QMutexLocker locker(&engineCacheMutex);
|
||||||
QMutexLocker locker(&globalEngineCacheMutex);
|
if (!eng->ref.deref()) {
|
||||||
QT_TRY {
|
if (QRECache *c = engineCache()) {
|
||||||
globalUnusedEngineCache()->insert(key, eng, 4 + key.pattern.length() / 4);
|
c->unusedEngines.insert(key, eng, 4 + key.pattern.length() / 4);
|
||||||
} QT_CATCH(const std::bad_alloc &) {
|
c->usedEngines.remove(key);
|
||||||
// in case of an exception (e.g. oom), just delete the engine
|
|
||||||
delete eng;
|
|
||||||
}
|
|
||||||
if (globalEngineCache())
|
|
||||||
globalEngineCache()->remove(key);
|
|
||||||
} else {
|
} else {
|
||||||
delete eng;
|
delete eng;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
Q_UNUSED(key);
|
Q_UNUSED(key);
|
||||||
|
if (!eng->ref.deref())
|
||||||
delete eng;
|
delete eng;
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void prepareEngine_helper(QRegExpPrivate *priv)
|
static void prepareEngine_helper(QRegExpPrivate *priv)
|
||||||
{
|
{
|
||||||
bool initMatchState = !priv->eng;
|
Q_ASSERT(!priv->eng);
|
||||||
|
|
||||||
#if !defined(QT_NO_REGEXP_OPTIM)
|
#if !defined(QT_NO_REGEXP_OPTIM)
|
||||||
if (!priv->eng && globalUnusedEngineCache()) {
|
QMutexLocker locker(&engineCacheMutex);
|
||||||
QMutexLocker locker(&globalEngineCacheMutex);
|
if (QRECache *c = engineCache()) {
|
||||||
priv->eng = globalUnusedEngineCache()->take(priv->engineKey);
|
priv->eng = c->unusedEngines.take(priv->engineKey);
|
||||||
if (!priv->eng && globalEngineCache())
|
if (!priv->eng)
|
||||||
priv->eng = globalEngineCache()->value(priv->engineKey);
|
priv->eng = c->usedEngines.value(priv->engineKey);
|
||||||
if (priv->eng != 0)
|
if (!priv->eng)
|
||||||
|
priv->eng = new QRegExpEngine(priv->engineKey);
|
||||||
|
else
|
||||||
priv->eng->ref.ref();
|
priv->eng->ref.ref();
|
||||||
|
|
||||||
|
c->usedEngines.insert(priv->engineKey, priv->eng);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
#endif // QT_NO_REGEXP_OPTIM
|
#endif // QT_NO_REGEXP_OPTIM
|
||||||
|
|
||||||
if (!priv->eng)
|
priv->eng = new QRegExpEngine(priv->engineKey);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline static void prepareEngine(QRegExpPrivate *priv)
|
inline static void prepareEngine(QRegExpPrivate *priv)
|
||||||
@ -3874,6 +3871,7 @@ inline static void prepareEngine(QRegExpPrivate *priv)
|
|||||||
if (priv->eng)
|
if (priv->eng)
|
||||||
return;
|
return;
|
||||||
prepareEngine_helper(priv);
|
prepareEngine_helper(priv);
|
||||||
|
priv->matchState.prepareForMatch(priv->eng);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void prepareEngineForMatch(QRegExpPrivate *priv, const QString &str)
|
static void prepareEngineForMatch(QRegExpPrivate *priv, const QString &str)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user