Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix use-after-free issue when destroying a OGRSpatialReference object…
… in a thread... when another thread has created it but has been destroy in-between The root cause is that a PJ* object captures the PJ_CONTEXT that created it, so when that PJ_CONTEXT is a TLS object, and that the thread disappears, the PJ* object references a dead object. So before destroying it, make sure to reassign the context of the current tread. Was seen while investigating QGIS issue qgis/QGIS#30569 No guarantee that this fix fixes the issue folks hits in practice since I can't reproduce it, but it's a fix anyway. We got the following stack trace while opening a project where we were asked to choose a datum transform and we let the QGIS OGR connection pool time out. ``` ==27326== Invalid read of size 4 ==27326== at 0xEA7996D: internal_pj_ctx_get_errno (ctx.cpp:195) ==27326== by 0xEA916EC: internal_proj_errno (4D_api.cpp:1262) ==27326== by 0xEA762D0: internal_pj_free (malloc.cpp:190) ==27326== by 0xEA916C5: internal_proj_destroy (4D_api.cpp:1253) ==27326== by 0xCA8B547: OGRSpatialReference::Private::~Private() (ogrspatialreference.cpp:163) ==27326== by 0xCAA34A3: std::default_delete<OGRSpatialReference::Private>::operator()(OGRSpatialReference::Private*) const (unique_ptr.h:76) ==27326== by 0xCAA334C: std::unique_ptr<OGRSpatialReference::Private, std::default_delete<OGRSpatialReference::Private> >::~unique_ptr() (unique_ptr.h:239) ==27326== by 0xCA8CFAB: OGRSpatialReference::~OGRSpatialReference() (ogrspatialreference.cpp:721) ==27326== by 0xCA8CFDB: OGRSpatialReference::~OGRSpatialReference() (ogrspatialreference.cpp:724) ==27326== by 0xCA8D37E: OGRSpatialReference::Release() (ogrspatialreference.cpp:924) ==27326== by 0xC5C089D: GDALGeoPackageDataset::~GDALGeoPackageDataset() (ogrgeopackagedatasource.cpp:842) ==27326== by 0xC5C0997: GDALGeoPackageDataset::~GDALGeoPackageDataset() (ogrgeopackagedatasource.cpp:844) ==27326== by 0xBFE637A: GDALClose (gdaldataset.cpp:3628) ==27326== by 0x7CF94EA: QgsOgrProviderUtils::GDALCloseWrapper(void*) (qgsogrprovider.cpp:4171) ==27326== by 0x78749AD: qgsConnectionPool_ConnectionDestroy(QgsOgrConn*) (qgsogrconnpool.h:50) ==27326== by 0x78793EE: QgsConnectionPoolGroup<QgsOgrConn*>::onConnectionExpired() (qgsconnectionpool.h:227) ==27326== by 0x78749EB: QgsOgrConnPoolGroup::handleConnectionExpired() (qgsogrconnpool.h:89) ==27326== by 0x784F64E: QgsOgrConnPoolGroup::qt_static_metacall(QObject*, QMetaObject::Call, int, void**) (moc_qgsogrconnpool.cpp:78) ==27326== by 0x9E8E588: QMetaObject::activate(QObject*, int, int, void**) (in /opt/qt59/lib/libQt5Core.so.5.9.1) ==27326== by 0x9E9AE16: QTimer::timeout(QTimer::QPrivateSignal) (in /opt/qt59/lib/libQt5Core.so.5.9.1) ==27326== by 0x9E9B117: QTimer::timerEvent(QTimerEvent*) (in /opt/qt59/lib/libQt5Core.so.5.9.1) ==27326== by 0x9E8F582: QObject::event(QEvent*) (in /opt/qt59/lib/libQt5Core.so.5.9.1) ==27326== by 0x8F7A3FB: QApplicationPrivate::notify_helper(QObject*, QEvent*) (in /opt/qt59/lib/libQt5Widgets.so.5.9.1) ==27326== by 0x8F81E06: QApplication::notify(QObject*, QEvent*) (in /opt/qt59/lib/libQt5Widgets.so.5.9.1) ==27326== by 0x7D4ED9A: QgsApplication::notify(QObject*, QEvent*) (qgsapplication.cpp:416) ==27326== by 0x9E62107: QCoreApplication::notifyInternal2(QObject*, QEvent*) (in /opt/qt59/lib/libQt5Core.so.5.9.1) ==27326== by 0x9EB666D: QTimerInfoList::activateTimers() (in /opt/qt59/lib/libQt5Core.so.5.9.1) ==27326== by 0x9EB6F28: ??? (in /opt/qt59/lib/libQt5Core.so.5.9.1) ==27326== by 0x125CE196: g_main_context_dispatch (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4800.2) ==27326== by 0x125CE3EF: ??? (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4800.2) ==27326== by 0x125CE49B: g_main_context_iteration (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4800.2) ==27326== by 0x9EB729E: QEventDispatcherGlib::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) (in /opt/qt59/lib/libQt5Core.so.5.9.1) ==27326== by 0x9E60139: QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) (in /opt/qt59/lib/libQt5Core.so.5.9.1) ==27326== by 0x91A9AA6: QDialog::exec() (in /opt/qt59/lib/libQt5Widgets.so.5.9.1) ==27326== by 0x6A40D77: QgsDatumTransformDialog::run(QgsCoordinateReferenceSystem const&, QgsCoordinateReferenceSystem const&, QWidget*, QgsMapCanvas*, QString const&) (qgsdatumtransformdialog.cpp:53) ==27326== by 0x51E3C10: QgisApp::askUserForDatumTransform(QgsCoordinateReferenceSystem const&, QgsCoordinateReferenceSystem const&, QgsMapLayer const*) (qgisapp.cpp:14254) ==27326== by 0x51C8DB3: QgisApp::projectCrsChanged() (qgisapp.cpp:10343) ==27326== by 0x526E713: QtPrivate::FunctorCall<QtPrivate::IndexesList<>, QtPrivate::List<>, void, void (QgisApp::*)()>::call(void (QgisApp::*)(), QgisApp*, void**) (qobjectdefs_impl.h:136) ==27326== by 0x5269A53: void QtPrivate::FunctionPointer<void (QgisApp::*)()>::call<QtPrivate::List<>, void>(void (QgisApp::*)(), QgisApp*, void**) (qobjectdefs_impl.h:169) ==27326== by 0x525F44C: QtPrivate::QSlotObject<void (QgisApp::*)(), QtPrivate::List<>, void>::impl(int, QtPrivate::QSlotObjectBase*, QObject*, void**, bool*) (qobject_impl.h:120) ==27326== Address 0x5c0c38b0 is 0 bytes inside a block of size 112 free'd ==27326== at 0x4C2F440: operator delete(void*) (vg_replace_malloc.c:586) ==27326== by 0xEA79944: internal_pj_ctx_free (ctx.cpp:183) ==27326== by 0xEA9182F: internal_proj_context_destroy (4D_api.cpp:1359) ==27326== by 0xCB12CD9: OSRPJContextHolder::deinit() (ogr_proj_p.cpp:96) ==27326== by 0xCB12C99: OSRPJContextHolder::~OSRPJContextHolder() (ogr_proj_p.cpp:88) ==27326== by 0xA75B5FE: __call_tls_dtors (cxa_thread_atexit_impl.c:155) ==27326== by 0x10F956C7: start_thread (pthread_create.c:343) ==27326== by 0xA82841C: clone (clone.S:109) ==27326== Block was alloc'd at ==27326== at 0x4C2E709: operator new(unsigned long, std::nothrow_t const&) (vg_replace_malloc.c:387) ==27326== by 0xEA798DC: internal_pj_ctx_alloc (ctx.cpp:173) ==27326== by 0xEA917F0: internal_proj_context_create (4D_api.cpp:1347) ==27326== by 0xCB12C57: OSRPJContextHolder::init() (ogr_proj_p.cpp:80) ==27326== by 0xCB12D20: OSRGetProjTLSContext() (ogr_proj_p.cpp:143) ==27326== by 0xCAA3116: OGRSpatialReference::Private::getPROJContext() (ogrspatialreference.cpp:149) ==27326== by 0xCAA0B79: OGRSpatialReference::importFromEPSGA(int) (ogrspatialreference.cpp:10260) ==27326== by 0xCAA0DFB: OGRSpatialReference::importFromEPSG(int) (ogrspatialreference.cpp:10353) ==27326== by 0xC5BEB2D: GDALGPKGImportFromEPSG(OGRSpatialReference*, int) (ogrgeopackagedatasource.cpp:255) ==27326== by 0xC5BEE8E: GDALGeoPackageDataset::GetSpatialRef(int) (ogrgeopackagedatasource.cpp:312) ==27326== by 0xC5DFB11: OGRGeoPackageTableLayer::ReadTableDefinition() (ogrgeopackagetablelayer.cpp:898) ==27326== by 0xC5DE918: OGRGeoPackageTableLayer::GetLayerDefn() (ogrgeopackagetablelayer.cpp:562) ==27326== by 0xC5E57E3: OGRGeoPackageTableLayer::TestCapability(char const*) (ogrgeopackagetablelayer.cpp:2614) ==27326== by 0xC6C8A46: OGR_L_TestCapability (ogrlayer.cpp:1078) ==27326== by 0x7CDD664: QgsOgrProviderUtils::setRelevantFields(void*, int, bool, QList<int> const&, bool, QString const&) (qgsogrprovider.cpp:1244) ==27326== by 0x7D20456: QgsOgrFeatureIterator::QgsOgrFeatureIterator(QgsOgrFeatureSource*, bool, QgsFeatureRequest const&) (qgsogrfeatureiterator.cpp:162) ==27326== by 0x7D22932: QgsOgrFeatureSource::getFeatures(QgsFeatureRequest const&) (qgsogrfeatureiterator.cpp:573) ==27326== by 0x81E2BCF: QgsVectorLayerFeatureIterator::QgsVectorLayerFeatureIterator(QgsVectorLayerFeatureSource*, bool, QgsFeatureRequest const&) (qgsvectorlayerfeatureiterator.cpp:274) ==27326== by 0x81E1C2C: QgsVectorLayerFeatureSource::getFeatures(QgsFeatureRequest const&) (qgsvectorlayerfeatureiterator.cpp:99) ==27326== by 0x82056D9: QgsVectorLayerRenderer::render() (qgsvectorlayerrenderer.cpp:272) ==27326== by 0x7F55B08: QgsMapRendererCustomPainterJob::doRender() (qgsmaprenderercustompainterjob.cpp:314) ==27326== by 0x7F55601: QgsMapRendererCustomPainterJob::staticRender(QgsMapRendererCustomPainterJob*) (qgsmaprenderercustompainterjob.cpp:264) ==27326== by 0x7F58D42: QtConcurrent::StoredFunctorCall1<void, void (*)(QgsMapRendererCustomPainterJob*), QgsMapRendererCustomPainterJob*>::runFunctor() (qtconcurrentstoredfunctioncall.h:432) ==27326== by 0x7F56690: QtConcurrent::RunFunctionTask<void>::run() (qtconcurrentrunbase.h:136) ==27326== by 0x9C7E942: ??? (in /opt/qt59/lib/libQt5Core.so.5.9.1) ==27326== by 0x9C82658: ??? (in /opt/qt59/lib/libQt5Core.so.5.9.1) ==27326== by 0x10F956B9: start_thread (pthread_create.c:333) ==27326== by 0xA82841C: clone (clone.S:109) ==27326== ```
- Loading branch information