QODBC: Fix crash when a prepared statement is deleted after the db was removed
When a prepared statement is still alive after the database was removed with QSqlDatabase::removeDatabase(), the cleanup routine is trying to access the driver which is no longer alive which results in a crash. Fixes: QTBUG-79019 Change-Id: I4630e3b947a12b23ed062f015abc373fc0e246c1 Reviewed-by: Andy Shaw <andy.shaw@qt.io>
This commit is contained in:
parent
2ec93e29f7
commit
ed7dd9a6ed
@ -221,18 +221,18 @@ public:
|
||||
int disconnectCount;
|
||||
bool hasSQLFetchScroll;
|
||||
|
||||
bool isStmtHandleValid();
|
||||
bool isStmtHandleValid() const;
|
||||
void updateStmtHandleState();
|
||||
};
|
||||
|
||||
bool QODBCResultPrivate::isStmtHandleValid()
|
||||
bool QODBCResultPrivate::isStmtHandleValid() const
|
||||
{
|
||||
return disconnectCount == drv_d_func()->disconnectCount;
|
||||
return drv_d_func() && disconnectCount == drv_d_func()->disconnectCount;
|
||||
}
|
||||
|
||||
void QODBCResultPrivate::updateStmtHandleState()
|
||||
{
|
||||
disconnectCount = drv_d_func()->disconnectCount;
|
||||
disconnectCount = drv_d_func() ? drv_d_func()->disconnectCount : 0;
|
||||
}
|
||||
|
||||
static QString qWarnODBCHandle(int handleType, SQLHANDLE handle, int *nativeCode = 0)
|
||||
@ -975,7 +975,7 @@ QODBCResult::QODBCResult(const QODBCDriver *db)
|
||||
QODBCResult::~QODBCResult()
|
||||
{
|
||||
Q_D(QODBCResult);
|
||||
if (d->hStmt && d->isStmtHandleValid() && driver()->isOpen()) {
|
||||
if (d->hStmt && d->isStmtHandleValid() && driver() && driver()->isOpen()) {
|
||||
SQLRETURN r = SQLFreeHandle(SQL_HANDLE_STMT, d->hStmt);
|
||||
if (r != SQL_SUCCESS)
|
||||
qSqlWarning(QLatin1String("QODBCDriver: Unable to free statement handle ")
|
||||
|
@ -196,8 +196,7 @@ private slots:
|
||||
|
||||
void task_250026_data() { generic_data("QODBC"); }
|
||||
void task_250026();
|
||||
void task_205701_data() { generic_data("QMYSQL"); }
|
||||
void task_205701();
|
||||
void crashQueryOnCloseDatabase();
|
||||
|
||||
void task_233829_data() { generic_data("QPSQL"); }
|
||||
void task_233829();
|
||||
@ -311,6 +310,8 @@ void tst_QSqlQuery::init()
|
||||
|
||||
void tst_QSqlQuery::cleanup()
|
||||
{
|
||||
if (QTest::currentTestFunction() == QLatin1String("crashQueryOnCloseDatabase"))
|
||||
return;
|
||||
QFETCH( QString, dbName );
|
||||
QSqlDatabase db = QSqlDatabase::database( dbName );
|
||||
CHECK_DATABASE( db );
|
||||
@ -3448,19 +3449,17 @@ void tst_QSqlQuery::task_250026()
|
||||
QCOMPARE( q.value( 0 ).toString().length(), data1026.length() );
|
||||
}
|
||||
|
||||
void tst_QSqlQuery::task_205701()
|
||||
void tst_QSqlQuery::crashQueryOnCloseDatabase()
|
||||
{
|
||||
QSqlDatabase qsdb = QSqlDatabase::addDatabase("QMYSQL", "atest");
|
||||
qsdb.setHostName("test");
|
||||
qsdb.setDatabaseName("test");
|
||||
qsdb.setUserName("test");
|
||||
qsdb.setPassword("test");
|
||||
qsdb.open();
|
||||
|
||||
// {
|
||||
QSqlQuery query(qsdb);
|
||||
// }
|
||||
QSqlDatabase::removeDatabase("atest");
|
||||
for (const auto &dbName : qAsConst(dbs.dbNames)) {
|
||||
QSqlDatabase clonedDb = QSqlDatabase::cloneDatabase(
|
||||
QSqlDatabase::database(dbName), "crashTest");
|
||||
qDebug() << "Testing crash in sqlquery dtor for driver" << clonedDb.driverName();
|
||||
QVERIFY(clonedDb.open());
|
||||
QSqlQuery q(clonedDb);
|
||||
clonedDb.close();
|
||||
QSqlDatabase::removeDatabase("crashTest");
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef NOT_READY_YET
|
||||
|
Loading…
Reference in New Issue
Block a user