Skip to content

Commit fefa572

Browse files
committed
Fix crash when transform errors occur while rendering
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
1 parent 660aaa5 commit fefa572

File tree

1 file changed

+29
-3
lines changed

1 file changed

+29
-3
lines changed

src/core/symbology-ng/qgssymbol.cpp

+29-3
Original file line numberDiff line numberDiff line change
@@ -643,6 +643,27 @@ bool QgsSymbol::hasDataDefinedProperties() const
643643
return false;
644644
}
645645

646+
///@cond PRIVATE
647+
648+
/**
649+
* RAII class to pop scope from an expression context on destruction
650+
*/
651+
class ExpressionContextScopePopper
652+
{
653+
public:
654+
655+
ExpressionContextScopePopper() = default;
656+
657+
~ExpressionContextScopePopper()
658+
{
659+
if ( context )
660+
context->popScope();
661+
}
662+
663+
QgsExpressionContext *context = nullptr;
664+
};
665+
///@endcond PRIVATE
666+
646667
void QgsSymbol::renderFeature( const QgsFeature &feature, QgsRenderContext &context, int layer, bool selected, bool drawVertexMarker, int currentVertexMarkerType, int currentVertexMarkerSize )
647668
{
648669
QgsGeometry geom = feature.geometry();
@@ -672,9 +693,17 @@ void QgsSymbol::renderFeature( const QgsFeature &feature, QgsRenderContext &cont
672693
mSymbolRenderContext->setGeometryPartCount( segmentizedGeometry.geometry()->partCount() );
673694
mSymbolRenderContext->setGeometryPartNum( 1 );
674695

696+
ExpressionContextScopePopper scopePopper;
675697
if ( mSymbolRenderContext->expressionContextScope() )
676698
{
699+
// this is somewhat nasty - by appending this scope here it's now owned
700+
// by both mSymbolRenderContext AND context.expressionContext()
701+
// the RAII scopePopper is required to make sure it always has ownership transferred back
702+
// from context.expressionContext(), even if exceptions of other early exits occur in this
703+
// function
677704
context.expressionContext().appendScope( mSymbolRenderContext->expressionContextScope() );
705+
scopePopper.context = &context.expressionContext();
706+
678707
QgsExpressionContextUtils::updateSymbolScope( this, mSymbolRenderContext->expressionContextScope() );
679708
mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_COUNT, mSymbolRenderContext->geometryPartCount(), true ) );
680709
mSymbolRenderContext->expressionContextScope()->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_NUM, 1, true ) );
@@ -952,9 +981,6 @@ void QgsSymbol::renderFeature( const QgsFeature &feature, QgsRenderContext &cont
952981
}
953982
}
954983
}
955-
956-
if ( mSymbolRenderContext->expressionContextScope() )
957-
context.expressionContext().popScope();
958984
}
959985

960986
QgsSymbolRenderContext *QgsSymbol::symbolRenderContext()

0 commit comments

Comments
 (0)