Skip to content

Commit

Permalink
Fix crash when transform errors occur while rendering
Browse files Browse the repository at this point in the history
If a transform exception occurred while rendering a symbol then
the QgsSymbolRenderContext cleanup code was never called,
leading to a double delete and crash.

Fixes #16377, #15345, and numerous other crashes seen "in the wild"

Possibly refs #16385

(cherry-picked from fefa572)
  • Loading branch information
nyalldawson committed May 11, 2017
1 parent bfa507a commit 452c806
Showing 1 changed file with 29 additions and 3 deletions.
32 changes: 29 additions & 3 deletions src/core/symbology-ng/qgssymbolv2.cpp
Expand Up @@ -699,6 +699,27 @@ bool QgsSymbolV2::hasDataDefinedProperties() const
return false;
}

///@cond PRIVATE

/**
* RAII class to pop scope from an expression context on destruction
*/
class ExpressionContextScopePopper
{
public:

ExpressionContextScopePopper() = default;

~ExpressionContextScopePopper()
{
if ( context )
context->popScope();
}

QgsExpressionContext *context = nullptr;
};
///@endcond PRIVATE

void QgsSymbolV2::renderFeature( const QgsFeature& feature, QgsRenderContext& context, int layer, bool selected, bool drawVertexMarker, int currentVertexMarkerType, int currentVertexMarkerSize )
{
const QgsGeometry* geom = feature.constGeometry();
Expand Down Expand Up @@ -728,9 +749,17 @@ void QgsSymbolV2::renderFeature( const QgsFeature& feature, QgsRenderContext& co
mSymbolRenderContext->setGeometryPartCount( segmentizedGeometry->geometry()->partCount() );
mSymbolRenderContext->setGeometryPartNum( 1 );

ExpressionContextScopePopper scopePopper;
if ( mSymbolRenderContext->expressionContextScope() )
{
// this is somewhat nasty - by appending this scope here it's now owned
// by both mSymbolRenderContext AND context.expressionContext()
// the RAII scopePopper is required to make sure it always has ownership transferred back
// from context.expressionContext(), even if exceptions of other early exits occur in this
// function
context.expressionContext().appendScope( mSymbolRenderContext->expressionContextScope() );
scopePopper.context = &context.expressionContext();

QgsExpressionContextUtils::updateSymbolScope( this, mSymbolRenderContext->expressionContextScope() );
mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_COUNT, mSymbolRenderContext->geometryPartCount(), true ) );
mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_NUM, 1, true ) );
Expand Down Expand Up @@ -1011,9 +1040,6 @@ void QgsSymbolV2::renderFeature( const QgsFeature& feature, QgsRenderContext& co
{
delete segmentizedGeometry;
}

if ( mSymbolRenderContext->expressionContextScope() )
context.expressionContext().popScope();
}

QgsSymbolV2RenderContext* QgsSymbolV2::symbolRenderContext()
Expand Down

0 comments on commit 452c806

Please sign in to comment.