Skip to content

Commit 2b15eaa

Browse files
committed
[Spatialite] Fix crash on iterator closing if connection failed.
If an iterator fails to open the spatialite database (mHandle == nullptr in QgsSpatiaLiteFeatureIterator::QgsSpatiaLiteFeatureIterator() ), a crash will occur at the destruction of the QgsSpatiaLiteFeatureSource, due to the iterator not being removed from the list of active iterators. Currently QgsSpatiaLiteFeatureIterator::close() does not call iteratorClosed() if mHandle is invalid, which later causes QgsAbstractFeatureSource::~QgsAbstractFeatureSource() to try calling the close() method of a now defunct iterator. If not applying the patch, the added test case crashes with: 177: src/providers/spatialite/qgsspatialiteconnection.cpp: 736: (openDb) [1ms] New sqlite connection for /tmp/test.sqlite.corrupt 177: src/providers/spatialite/qgsspatialiteconnection.cpp: 750: (openDb) [1ms] Failure while connecting to: /tmp/test.sqlite.corrupt 177: 177: invalid metadata tables 177: src/core/qgsfeaturerequest.cpp: 259: (~QgsAbstractFeatureSource) [0ms] closing active iterator 177: CMake Error at PyQgsSpatialiteProvider.cmake:22 (MESSAGE): 177: Test failed: Segmentation fault
1 parent 140b517 commit 2b15eaa

File tree

2 files changed

+18
-1
lines changed

2 files changed

+18
-1
lines changed

src/providers/spatialite/qgsspatialitefeatureiterator.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,11 +235,17 @@ bool QgsSpatiaLiteFeatureIterator::rewind()
235235

236236
bool QgsSpatiaLiteFeatureIterator::close()
237237
{
238-
if ( !mHandle )
238+
if ( mClosed )
239239
return false;
240240

241241
iteratorClosed();
242242

243+
if ( !mHandle )
244+
{
245+
mClosed = true;
246+
return false;
247+
}
248+
243249
if ( sqliteStatement )
244250
{
245251
sqlite3_finalize( sqliteStatement );

tests/src/python/test_provider_spatialite.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import qgis # NOQA
1616

1717
import os
18+
import shutil
1819
import tempfile
1920

2021
from qgis.core import QgsVectorLayer, QgsPoint, QgsFeature
@@ -201,6 +202,16 @@ def test_case(self):
201202
fields = [f.name() for f in l.dataProvider().fields()]
202203
assert('Geometry' not in fields)
203204

205+
def test_invalid_iterator(self):
206+
""" Test invalid iterator """
207+
corrupt_dbname = self.dbname + '.corrupt'
208+
shutil.copy(self.dbname, corrupt_dbname)
209+
layer = QgsVectorLayer("dbname=%s table=test_pg (geometry)" % corrupt_dbname, "test_pg", "spatialite")
210+
# Corrupt the database
211+
open(corrupt_dbname, 'wb').write('')
212+
layer.getFeatures()
213+
layer = None
214+
os.unlink(corrupt_dbname)
204215

205216
if __name__ == '__main__':
206217
unittest.main()

0 commit comments

Comments
 (0)