From 8d2bdc9cd5482eace12ba7e45304857bd24db0e6 Mon Sep 17 00:00:00 2001 From: Christian Ehrlicher Date: Tue, 18 Apr 2023 19:40:25 +0200 Subject: [PATCH] SQL: Make QSqlDatabase::DriverDict creation thread-safe Make the QSqlDatabase::DriverDict thread-safe and make sure it's properly cleaned up on destruction. Fixes: QTBUG-112961 Change-Id: I1ff70e477579231754ef829fdede944d6042894d Reviewed-by: Volker Hilsheimer (cherry picked from commit 048a68c1e965350ad9ff7d4ab1fdaac56a2583a0) --- src/sql/kernel/qsqldatabase.cpp | 31 +++++++++++++------------ tests/auto/sql/kernel/qsql/tst_qsql.cpp | 4 ++++ 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/src/sql/kernel/qsqldatabase.cpp b/src/sql/kernel/qsqldatabase.cpp index 90ce374c543..7aab81c234f 100644 --- a/src/sql/kernel/qsqldatabase.cpp +++ b/src/sql/kernel/qsqldatabase.cpp @@ -10,6 +10,7 @@ #include "qsqldriver.h" #include "qsqldriverplugin.h" #include "qsqlindex.h" +#include "QtCore/qapplicationstatic.h" #include "private/qfactoryloader_p.h" #include "private/qsqlnulldriver_p.h" #include "qmutex.h" @@ -26,8 +27,6 @@ Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, const char *QSqlDatabase::defaultConnection = const_cast("qt_sql_default_connection"); -typedef QHash DriverDict; - class QConnectionDict: public QHash { public: @@ -46,6 +45,14 @@ class QConnectionDict: public QHash }; Q_GLOBAL_STATIC(QConnectionDict, dbDict) +namespace { + struct DriverDict : public QHash + { + ~DriverDict(); + }; +} +Q_APPLICATION_STATIC(DriverDict, qtDriverDict) + class QSqlDatabasePrivate { public: @@ -121,23 +128,15 @@ void QSqlDatabasePrivate::cleanConnections() dict->clear(); } -static bool qDriverDictInit = false; -static void cleanDriverDict() +DriverDict::~DriverDict() { - qDeleteAll(QSqlDatabasePrivate::driverDict()); - QSqlDatabasePrivate::driverDict().clear(); + qDeleteAll(*this); QSqlDatabasePrivate::cleanConnections(); - qDriverDictInit = false; } DriverDict &QSqlDatabasePrivate::driverDict() { - static DriverDict dict; - if (!qDriverDictInit) { - qDriverDictInit = true; - qAddPostRoutine(cleanDriverDict); - } - return dict; + return *qtDriverDict(); } QSqlDatabasePrivate *QSqlDatabasePrivate::shared_null() @@ -511,7 +510,8 @@ QStringList QSqlDatabase::drivers() list << it.value(); } - DriverDict dict = QSqlDatabasePrivate::driverDict(); + QReadLocker locker(&dbDict()->lock); + const DriverDict &dict = QSqlDatabasePrivate::driverDict(); for (DriverDict::const_iterator i = dict.constBegin(); i != dict.constEnd(); ++i) { if (!list.contains(i.key())) list << i.key(); @@ -649,7 +649,8 @@ void QSqlDatabasePrivate::init(const QString &type) drvName = type; if (!driver) { - DriverDict dict = QSqlDatabasePrivate::driverDict(); + QReadLocker locker(&dbDict()->lock); + const DriverDict &dict = QSqlDatabasePrivate::driverDict(); for (DriverDict::const_iterator it = dict.constBegin(); it != dict.constEnd() && !driver; ++it) { if (type == it.key()) { diff --git a/tests/auto/sql/kernel/qsql/tst_qsql.cpp b/tests/auto/sql/kernel/qsql/tst_qsql.cpp index 55cbfad421e..7fe25c12d8a 100644 --- a/tests/auto/sql/kernel/qsql/tst_qsql.cpp +++ b/tests/auto/sql/kernel/qsql/tst_qsql.cpp @@ -135,6 +135,10 @@ void tst_QSql::open() void tst_QSql::openInvalid() { + int argc = 1; + char *argv[] = { const_cast(QTest::currentAppName()) }; + QCoreApplication app(argc, argv, false); + QSqlDatabase db; QVERIFY(!db.open());