Skip to content
Permalink
Browse files
Fix unsafe access of map layer from background thread while running l…
…abel engine
  • Loading branch information
nyalldawson committed Jun 28, 2021
1 parent 849819c commit 731810ce71553ba1c987d01e7340dc4b43c0248e
Showing with 28 additions and 4 deletions.
  1. +12 −3 src/core/labeling/qgslabelingengine.cpp
  2. +16 −1 src/core/labeling/qgslabelingengine.h
@@ -282,9 +282,9 @@ void QgsLabelingEngine::registerLabels( QgsRenderContext &context )
for ( QgsAbstractLabelProvider *provider : std::as_const( mProviders ) )
{
std::unique_ptr< QgsExpressionContextScopePopper > layerScopePopper;
if ( QgsMapLayer *ml = provider->layer() )
if ( provider->layerExpressionContextScope() )
{
layerScopePopper = std::make_unique< QgsExpressionContextScopePopper >( context.expressionContext(), QgsExpressionContextUtils::layerScope( ml ) );
layerScopePopper = std::make_unique< QgsExpressionContextScopePopper >( context.expressionContext(), new QgsExpressionContextScope( *provider->layerExpressionContextScope() ) );
}
processProvider( provider, context, *mPal );
}
@@ -420,7 +420,7 @@ void QgsLabelingEngine::drawLabels( QgsRenderContext &context, const QString &la

// provider will require the correct layer scope for expression preparation - at this stage, the existing expression context
// only contains generic scopes
QgsExpressionContextScopePopper popper( context.expressionContext(), QgsExpressionContextUtils::layerScope( provider->layer() ) );
QgsExpressionContextScopePopper popper( context.expressionContext(), provider->layerExpressionContextScope() ? new QgsExpressionContextScope( *provider->layerExpressionContextScope() ) : new QgsExpressionContextScope() );
provider->startRender( context );
}

@@ -623,6 +623,10 @@ QgsAbstractLabelProvider::QgsAbstractLabelProvider( QgsMapLayer *layer, const QS
, mPriority( 0.5 )
, mUpsidedownLabels( QgsPalLayerSettings::Upright )
{
if ( QgsVectorLayer *vl = qobject_cast< QgsVectorLayer * >( layer ) )
{
mLayerExpressionContextScope.reset( vl->createExpressionContextScope() );
}
}

void QgsAbstractLabelProvider::drawUnplacedLabel( QgsRenderContext &, pal::LabelPosition * ) const
@@ -653,6 +657,11 @@ void QgsAbstractLabelProvider::stopRender( QgsRenderContext &context )
}
}

QgsExpressionContextScope *QgsAbstractLabelProvider::layerExpressionContextScope() const
{
return mLayerExpressionContextScope.get();
}

//
// QgsLabelingUtils
//
@@ -127,7 +127,11 @@ class CORE_EXPORT QgsAbstractLabelProvider
//! Returns ID of associated layer, or empty string if no layer is associated with the provider.
QString layerId() const { return mLayerId; }

//! Returns the associated layer, or NULLPTR if no layer is associated with the provider.
/**
* Returns the associated layer, or NULLPTR if no layer is associated with the provider.
*
* \warning Accessing the layer is not thread safe, and this should never be called while the labeling engine is running from a background thread!
*/
QgsMapLayer *layer() const { return mLayer.data(); }

/**
@@ -152,6 +156,13 @@ class CORE_EXPORT QgsAbstractLabelProvider
//! How to handle labels that would be upside down
QgsPalLayerSettings::UpsideDownLabels upsidedownLabels() const { return mUpsidedownLabels; }

/**
* Returns the expression context scope created from the layer associated with this provider.
*
* \since QGIS 3.22
*/
QgsExpressionContextScope *layerExpressionContextScope() const;

protected:
//! Associated labeling engine
const QgsLabelingEngine *mEngine = nullptr;
@@ -174,6 +185,10 @@ class CORE_EXPORT QgsAbstractLabelProvider
QgsLabelObstacleSettings::ObstacleType mObstacleType = QgsLabelObstacleSettings::PolygonBoundary;
//! How to handle labels that would be upside down
QgsPalLayerSettings::UpsideDownLabels mUpsidedownLabels;

private:

std::unique_ptr< QgsExpressionContextScope > mLayerExpressionContextScope;
};

Q_DECLARE_OPERATORS_FOR_FLAGS( QgsAbstractLabelProvider::Flags )

0 comments on commit 731810c

Please sign in to comment.