Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Correct crash when read from ogr file in thread (QgsProcessing for in…
…stance)

fixes #20581
  • Loading branch information
troopa81 authored and nyalldawson committed Feb 7, 2019
1 parent 3b4def8 commit e948120
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/providers/ogr/qgsogrconnpool.h
Expand Up @@ -156,7 +156,7 @@ class QgsOgrConnPool : public QgsConnectionPool<QgsOgrConn *, QgsOgrConnPoolGrou

if ( it.value()->unref() )
{
delete it.value();
it.value()->deleteLater();
mGroups.erase( it );
}
mMutex.unlock();
Expand Down
1 change: 1 addition & 0 deletions tests/src/providers/CMakeLists.txt
Expand Up @@ -72,6 +72,7 @@ TARGET_LINK_LIBRARIES(qgis_arcgisrestutilstest arcgisfeatureserverprovider_a)

ADD_QGIS_TEST(gdalprovidertest testqgsgdalprovider.cpp)

SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
ADD_QGIS_TEST(ogrprovidertest testqgsogrprovider.cpp)

ADD_QGIS_TEST(wmscapabilitiestest
Expand Down
84 changes: 84 additions & 0 deletions tests/src/providers/testqgsogrprovider.cpp
Expand Up @@ -46,6 +46,7 @@ class TestQgsOgrProvider : public QObject

void setupProxy();
void decodeUri();
void testThread();

private:
QString mTestDataDir;
Expand Down Expand Up @@ -130,5 +131,88 @@ void TestQgsOgrProvider::decodeUri()
QCOMPARE( parts.value( QStringLiteral( "layerName" ) ).toString(), QString( "a_layer" ) );
}


class ReadVectorLayer : public QThread
{

public :
ReadVectorLayer( const QString &filePath, QMutex &mutex, QWaitCondition &waitForVlCreation, QWaitCondition &waitForProcessEvents )
: _filePath( filePath ), _mutex( mutex ), _waitForVlCreation( waitForVlCreation ), _waitForProcessEvents( waitForProcessEvents ) {}

void run() override
{

QgsVectorLayer *vl2 = new QgsVectorLayer( _filePath, QStringLiteral( "thread_test" ), QLatin1Literal( "ogr" ) );

QgsFeature f;
QVERIFY( vl2->getFeatures().nextFeature( f ) );

_mutex.lock();
_waitForVlCreation.wakeAll();
_mutex.unlock();

_mutex.lock();
_waitForProcessEvents.wait( &_mutex );
_mutex.unlock();

delete vl2;
}

private:
QString _filePath;
QMutex &_mutex;
QWaitCondition &_waitForVlCreation;
QWaitCondition &_waitForProcessEvents;

};

void failOnWarning( QtMsgType type, const QMessageLogContext &context, const QString &msg )
{
Q_UNUSED( context );

switch ( type )
{
case QtWarningMsg:
QFAIL( QString( "No Qt warning message expect : %1" ).arg( msg ).toUtf8() );
default:;
}
}

void TestQgsOgrProvider::testThread()
{
// After reading a QgsVectorLayer (getFeatures) from another thread the QgsOgrConnPoolGroup starts
// an expiration timer. The timer belongs to the main thread in order to listening the event
// loop and is parented to its QgsOgrConnPoolGroup. So when we delete the QgsVectorLayer, the
// QgsConnPoolGroup and the timer are subsequently deleted from another thread. This leads to
// segfault later when the expiration time reaches its timeout.

QMutex mutex;
QWaitCondition waitForVlCreation;
QWaitCondition waitForProcessEvents;

QString filePath = mTestDataDir + '/' + QStringLiteral( "lines.shp" );
QThread *thread = new ReadVectorLayer( filePath, mutex, waitForVlCreation, waitForProcessEvents );

thread->start();

mutex.lock();
waitForVlCreation.wait( &mutex );
mutex.unlock();

// make sure timer as been started
QCoreApplication::processEvents();

qInstallMessageHandler( failOnWarning );

mutex.lock();
waitForProcessEvents.wakeAll();
mutex.unlock();

thread->wait();
qInstallMessageHandler( 0 );

}


QGSTEST_MAIN( TestQgsOgrProvider )
#include "testqgsogrprovider.moc"

0 comments on commit e948120

Please sign in to comment.