QLoggingRegistry: fix potential data race
The 'rules' vector is made up of all the individual {env,config,...}Rules vectors under mutex protection whenever init() is called (only from the QCoreApplication ctor) or, at any time, by a call to QLoggingCategory:: setFilterRules(). Yet, the writes to the individual *Rules vectors were never protected by registryMutex, racing against the reads of the same vectors in the updateRules() function. Fix by protecting all access of all member variables with registryMutex. Add some strategic comments to make analysis easier for the next guy. Change-Id: If68d15a553ec7038693574a34f10a39f4cd480e8 Reviewed-by: Olivier Goffart (Woboq GmbH) <ogoffart@woboq.com>
This commit is contained in:
parent
10d0f4cba9
commit
567abeaa04
@ -276,10 +276,11 @@ static QVector<QLoggingRule> loadRulesFromFile(const QString &filePath)
|
|||||||
*/
|
*/
|
||||||
void QLoggingRegistry::init()
|
void QLoggingRegistry::init()
|
||||||
{
|
{
|
||||||
|
QVector<QLoggingRule> er, qr, cr;
|
||||||
// get rules from environment
|
// get rules from environment
|
||||||
const QByteArray rulesFilePath = qgetenv("QT_LOGGING_CONF");
|
const QByteArray rulesFilePath = qgetenv("QT_LOGGING_CONF");
|
||||||
if (!rulesFilePath.isEmpty())
|
if (!rulesFilePath.isEmpty())
|
||||||
envRules = loadRulesFromFile(QFile::decodeName(rulesFilePath));
|
er = loadRulesFromFile(QFile::decodeName(rulesFilePath));
|
||||||
|
|
||||||
const QByteArray rulesSrc = qgetenv("QT_LOGGING_RULES").replace(';', '\n');
|
const QByteArray rulesSrc = qgetenv("QT_LOGGING_RULES").replace(';', '\n');
|
||||||
if (!rulesSrc.isEmpty()) {
|
if (!rulesSrc.isEmpty()) {
|
||||||
@ -287,7 +288,7 @@ void QLoggingRegistry::init()
|
|||||||
QLoggingSettingsParser parser;
|
QLoggingSettingsParser parser;
|
||||||
parser.setSection(QStringLiteral("Rules"));
|
parser.setSection(QStringLiteral("Rules"));
|
||||||
parser.setContent(stream);
|
parser.setContent(stream);
|
||||||
envRules += parser.rules();
|
er += parser.rules();
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString configFileName = QStringLiteral("qtlogging.ini");
|
const QString configFileName = QStringLiteral("qtlogging.ini");
|
||||||
@ -296,17 +297,22 @@ void QLoggingRegistry::init()
|
|||||||
// get rules from Qt data configuration path
|
// get rules from Qt data configuration path
|
||||||
const QString qtConfigPath
|
const QString qtConfigPath
|
||||||
= QDir(QLibraryInfo::location(QLibraryInfo::DataPath)).absoluteFilePath(configFileName);
|
= QDir(QLibraryInfo::location(QLibraryInfo::DataPath)).absoluteFilePath(configFileName);
|
||||||
qtConfigRules = loadRulesFromFile(qtConfigPath);
|
qr = loadRulesFromFile(qtConfigPath);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// get rules from user's/system configuration
|
// get rules from user's/system configuration
|
||||||
const QString envPath = QStandardPaths::locate(QStandardPaths::GenericConfigLocation,
|
const QString envPath = QStandardPaths::locate(QStandardPaths::GenericConfigLocation,
|
||||||
QString::fromLatin1("QtProject/") + configFileName);
|
QString::fromLatin1("QtProject/") + configFileName);
|
||||||
if (!envPath.isEmpty())
|
if (!envPath.isEmpty())
|
||||||
configRules = loadRulesFromFile(envPath);
|
cr = loadRulesFromFile(envPath);
|
||||||
|
|
||||||
|
const QMutexLocker locker(®istryMutex);
|
||||||
|
|
||||||
|
envRules = std::move(er);
|
||||||
|
qtConfigRules = std::move(qr);
|
||||||
|
configRules = std::move(cr);
|
||||||
|
|
||||||
if (!envRules.isEmpty() || !qtConfigRules.isEmpty() || !configRules.isEmpty()) {
|
if (!envRules.isEmpty() || !qtConfigRules.isEmpty() || !configRules.isEmpty()) {
|
||||||
QMutexLocker locker(®istryMutex);
|
|
||||||
updateRules();
|
updateRules();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -347,11 +353,11 @@ void QLoggingRegistry::setApiRules(const QString &content)
|
|||||||
parser.setSection(QStringLiteral("Rules"));
|
parser.setSection(QStringLiteral("Rules"));
|
||||||
parser.setContent(content);
|
parser.setContent(content);
|
||||||
|
|
||||||
QMutexLocker locker(®istryMutex);
|
|
||||||
|
|
||||||
if (qtLoggingDebug())
|
if (qtLoggingDebug())
|
||||||
debugMsg("Loading logging rules set by QLoggingCategory::setFilterRules ...");
|
debugMsg("Loading logging rules set by QLoggingCategory::setFilterRules ...");
|
||||||
|
|
||||||
|
const QMutexLocker locker(®istryMutex);
|
||||||
|
|
||||||
apiRules = parser.rules();
|
apiRules = parser.rules();
|
||||||
|
|
||||||
updateRules();
|
updateRules();
|
||||||
@ -400,6 +406,8 @@ QLoggingRegistry *QLoggingRegistry::instance()
|
|||||||
/*!
|
/*!
|
||||||
\internal
|
\internal
|
||||||
Updates category settings according to rules.
|
Updates category settings according to rules.
|
||||||
|
|
||||||
|
As a category filter, it is run with registryMutex held.
|
||||||
*/
|
*/
|
||||||
void QLoggingRegistry::defaultCategoryFilter(QLoggingCategory *cat)
|
void QLoggingRegistry::defaultCategoryFilter(QLoggingCategory *cat)
|
||||||
{
|
{
|
||||||
|
@ -129,6 +129,7 @@ private:
|
|||||||
|
|
||||||
QMutex registryMutex;
|
QMutex registryMutex;
|
||||||
|
|
||||||
|
// protected by mutex:
|
||||||
QVector<QLoggingRule> qtConfigRules;
|
QVector<QLoggingRule> qtConfigRules;
|
||||||
QVector<QLoggingRule> configRules;
|
QVector<QLoggingRule> configRules;
|
||||||
QVector<QLoggingRule> envRules;
|
QVector<QLoggingRule> envRules;
|
||||||
|
Loading…
Reference in New Issue
Block a user