Follow-up to https://github.com/qgis/QGIS/pull/31848
When a thread exits, make sure that we iterate over QgsCoordinateTransform::sTransforms
to remove from QgsCoordinateTransformPrivate::mProjProjections objects that
relates to the current thread, in order to free memory.
This is only implemented in the PROJ >= 6 case. In theory, we could probably
now revert //github.com/qgis/QGIS/pull/31848 for its PROJ 6 code paths, but
keeping it doesn't hurt...
A similar fix could potentially be done in PROJ < 6 case, but it would require
probably the starting call to be in QgsProjContextStore::~QgsProjContextStore()
instead of QgsProjContext::~QgsProjContext()
This fixes the following Valgrind reported error:
```
==1703== Invalid read of size 4
==1703== at 0xE614195: internal_pj_ctx_get_errno (in /home/even/proj/install-proj-master/lib/libproj.so.15.2.0)
==1703== by 0xE6116AE: internal_pj_free (in /home/even/proj/install-proj-master/lib/libproj.so.15.2.0)
==1703== by 0xE624E78: internal_proj_destroy (in /home/even/proj/install-proj-master/lib/libproj.so.15.2.0)
==1703== by 0x7D3EFE7: QgsCoordinateTransformPrivate::freeProj() (qgscoordinatetransform_p.cpp:659)
==1703== by 0x7D3CD23: QgsCoordinateTransformPrivate::~QgsCoordinateTransformPrivate() (qgscoordinatetransform_p.cpp:120)
==1703== by 0x7D3AC46: QExplicitlySharedDataPointer<QgsCoordinateTransformPrivate>::~QExplicitlySharedDataPointer() (qshareddata.h:165)
==1703== by 0x7D36D63: QgsCoordinateTransform::~QgsCoordinateTransform() (qgscoordinatetransform.cpp:148)
==1703== by 0x7D3C425: QHashNode<QPair<QString, QString>, QgsCoordinateTransform>::~QHashNode() (qhash.h:149)
==1703== by 0x7D3C459: QHash<QPair<QString, QString>, QgsCoordinateTransform>::deleteNode2(QHashData::Node*) (qhash.h:536)
==1703== by 0x9BEEB78: QHashData::free_helper(void (*)(QHashData::Node*)) (in /opt/qt59/lib/libQt5Core.so.5.9.1)
==1703== by 0x7D3B81C: QHash<QPair<QString, QString>, QgsCoordinateTransform>::freeData(QHashData*) (qhash.h:576)
==1703== by 0x7D3B2B3: QHash<QPair<QString, QString>, QgsCoordinateTransform>::~QHash() (qhash.h:254)
==1703== by 0x7D3B7DA: QHash<QPair<QString, QString>, QgsCoordinateTransform>::operator=(QHash<QPair<QString, QString>, QgsCoordinateTransform>&&) (qhash.h:260)
==1703== by 0x7D3B239: QHash<QPair<QString, QString>, QgsCoordinateTransform>::clear() (qhash.h:582)
==1703== by 0x7D3A685: QgsCoordinateTransform::invalidateCache(bool) (qgscoordinatetransform.cpp:958)
==1703== by 0x7C73601: QgsApplication::invalidateCaches() (qgsapplication.cpp:365)
==1703== by 0x7C7A490: QgsApplication::exitQgis() (qgsapplication.cpp:1275)
==1703== by 0x511BCC5: QgisApp::~QgisApp() (qgisapp.cpp:1662)
==1703== by 0x511BE73: QgisApp::~QgisApp() (qgisapp.cpp:1664)
==1703== by 0x418CB4: main (main.cpp:1579)
==1703== Address 0x48fc4710 is 0 bytes inside a block of size 136 free'd
==1703== at 0x4C2F440: operator delete(void*) (vg_replace_malloc.c:586)
==1703== by 0xE625A3A: internal_proj_context_destroy (in /home/even/proj/install-proj-master/lib/libproj.so.15.2.0)
==1703== by 0x7F9B78A: QgsProjContext::~QgsProjContext() (qgsprojutils.cpp:48)
==1703== by 0xA6195FE: __call_tls_dtors (cxa_thread_atexit_impl.c:155)
==1703== by 0x10A936C7: start_thread (pthread_create.c:343)
==1703== by 0xA6E641C: clone (clone.S:109)
==1703== Block was alloc'd at
==1703== at 0x4C2E709: operator new(unsigned long, std::nothrow_t const&) (vg_replace_malloc.c:387)
==1703== by 0xE61445E: internal_pj_ctx_alloc (in /home/even/proj/install-proj-master/lib/libproj.so.15.2.0)
==1703== by 0x7F9B761: QgsProjContext::QgsProjContext() (qgsprojutils.cpp:39)
==1703== by 0x7F9C6B9: __tls_init (qgsprojutils.cpp:31)
==1703== by 0x7F9C703: TLS wrapper function for QgsProjContext::sProjContext (in /home/even/qgis/QGIS/build/output/lib/libqgis_core.so.3.9.0)
==1703== by 0x7F9B796: QgsProjContext::get() (qgsprojutils.cpp:57)
==1703== by 0x7D3D5AA: QgsCoordinateTransformPrivate::threadLocalProjData() (qgscoordinatetransform_p.cpp:299)
==1703== by 0x7D3D11A: QgsCoordinateTransformPrivate::initialize() (qgscoordinatetransform_p.cpp:199)
==1703== by 0x7D368E4: QgsCoordinateTransform::QgsCoordinateTransform(QgsCoordinateReferenceSystem const&, QgsCoordinateReferenceSystem const&, QgsCoordinateTransformContext const&) (qgscoordinatetransform.cpp:75)
==1703== by 0x8317CBE: QgsRasterProjector::block(int, QgsRectangle const&, int, int, QgsRasterBlockFeedback*) (qgsrasterprojector.cpp:779)
==1703== by 0x82EBE87: QgsRasterIterator::readNextRasterPartInternal(int, int&, int&, std::unique_ptr<QgsRasterBlock, std::default_delete<QgsRasterBlock> >*, int&, int&, QgsRectangle*) (qgsrasteriterator.cpp:130)
==1703== by 0x82EB791: QgsRasterIterator::readNextRasterPart(int, int&, int&, std::unique_ptr<QgsRasterBlock, std::default_delete<QgsRasterBlock> >&, int&, int&, QgsRectangle*) (qgsrasteriterator.cpp:80)
==1703== by 0x8334E8D: QgsRasterDrawer::draw(QPainter*, QgsRasterViewPort*, QgsMapToPixel const*, QgsRasterBlockFeedback*) (qgsrasterdrawer.cpp:60)
==1703== by 0x830AEE3: QgsRasterLayerRenderer::render() (qgsrasterlayerrenderer.cpp:269)
==1703== by 0x7E764FB: QgsMapRendererCustomPainterJob::doRender() (qgsmaprenderercustompainterjob.cpp:310)
==1703== by 0x7E76027: QgsMapRendererCustomPainterJob::staticRender(QgsMapRendererCustomPainterJob*) (qgsmaprenderercustompainterjob.cpp:261)
==1703== by 0x7E788D6: QtConcurrent::StoredFunctorCall1<void, void (*)(QgsMapRendererCustomPainterJob*), QgsMapRendererCustomPainterJob*>::runFunctor() (qtconcurrentstoredfunctioncall.h:432)
==1703== by 0x7E76E42: QtConcurrent::RunFunctionTask<void>::run() (qtconcurrentrunbase.h:136)
==1703== by 0x9B93942: ??? (in /opt/qt59/lib/libQt5Core.so.5.9.1)
==1703== by 0x9B97658: ??? (in /opt/qt59/lib/libQt5Core.so.5.9.1)
==1703== by 0x10A936B9: start_thread (pthread_create.c:333)
==1703== by 0xA6E641C: clone (clone.S:109)
```
This issue is also found on QGIS 3.4 / PROJ 5 with a slighly comparable stack
trace.
The issue here is that the static QgsCoordinateTransform::sTransforms cache map
contains QgsCoordinateTransformPrivate::mProjProjections objects, which themselves
are PJ*/projPJ PROJ objects. Those objects may have been created by a thread,
using a PROJ context, which is a TLS object, and thus has been deleted when
the thread is itself deleted. However sTransforms is cleaned afterwards, and
when destroying a PJ*/projPJ object, the context it is attached to must still
be alive.
This fix of this commit consists in creating a temporary PROJ context and assigning
it to the PJ* object before its destruction.
A proper fix would be to remove from sTransforms the PROJ objects that belong to
a given thread when that thread is deleted (or more exactly QgsProjContext is destroyed),
but that's more involved. Another reason for such a proper fix is to avoid a
kind of memory leak, since currently sTransforms might grow without control when
threads are created and destroyed.