Skip to content

Commit fabf32e

Browse files
committedJul 11, 2017
Add an assert to protect multiple calls to QgsSymbolV2::startRender()
while rendering has already been started for a particular symbol instance Relates to a random but frequent crash which occurs when using the categorised symbol renderer - tracked down to a race condition in which multiple concurrent calls to startRender() are performed on a single symbol instance.
1 parent 67c6e8f commit fabf32e

File tree

2 files changed

+10
-0
lines changed

2 files changed

+10
-0
lines changed
 

‎src/core/symbology-ng/qgssymbol.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,9 @@ bool QgsSymbol::changeSymbolLayer( int index, QgsSymbolLayer *layer )
383383

384384
void QgsSymbol::startRender( QgsRenderContext &context, const QgsFields &fields )
385385
{
386+
Q_ASSERT_X( !mStarted, "startRender", "Rendering has already been started for this symbol instance!" );
387+
mStarted = true;
388+
386389
mSymbolRenderContext.reset( new QgsSymbolRenderContext( context, outputUnit(), mOpacity, false, mRenderHints, nullptr, fields, mapUnitScale() ) );
387390

388391
QgsSymbolRenderContext symbolContext( context, outputUnit(), mOpacity, false, mRenderHints, nullptr, fields, mapUnitScale() );
@@ -402,6 +405,9 @@ void QgsSymbol::startRender( QgsRenderContext &context, const QgsFields &fields
402405

403406
void QgsSymbol::stopRender( QgsRenderContext &context )
404407
{
408+
Q_ASSERT_X( mStarted, "startRender", "startRender was not called for this symbol instance!" );
409+
mStarted = false;
410+
405411
Q_UNUSED( context )
406412
if ( mSymbolRenderContext )
407413
{

‎src/core/symbology-ng/qgssymbol.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,10 @@ class CORE_EXPORT QgsSymbol
388388
QgsSymbol( const QgsSymbol & );
389389
#endif
390390

391+
//! True if render has already been started - guards against multiple calls to
392+
//! startRender() (usually a result of not cloning a shared symbol instance before rendering).
393+
bool mStarted = false;
394+
391395
//! Initialized in startRender, destroyed in stopRender
392396
std::unique_ptr< QgsSymbolRenderContext > mSymbolRenderContext;
393397

4 commit comments

Comments
 (4)

nirvn commented on Jul 11, 2017

@nirvn
Contributor

@nyalldawson , QGIS now crashes when opening a project here:

#0  0x00007ffff2fe877f in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:58
#1  0x00007ffff2fea37a in __GI_abort () at abort.c:89
#2  0x000055555555d7b1 in qgisCrash(int) (signal=-1) at /home/webmaster/dev/cpp/QGIS/src/app/main.cpp:329
#3  0x000055555555da5a in myMessageOutput(QtMsgType, char const*) (type=QtFatalMsg, msg=0x555559255af8 "ASSERT failure in startRender: \"Rendering has already been started for this symbol instance!\", file /home/webmaster/dev/cpp/QGIS/src/core/symbology-ng/qgssymbol.cpp, line 386") at /home/webmaster/dev/cpp/QGIS/src/app/main.cpp:382
#4  0x00007ffff39aa99d in  () at /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#5  0x00007ffff39ac439 in QMessageLogger::fatal(char const*, ...) const () at /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#6  0x00007ffff39a7981 in  () at /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#7  0x00007ffff536fc74 in QgsSymbol::startRender(QgsRenderContext&, QgsFields const&) (this=0x55555919d2b0, context=..., fields=...)
    at /home/webmaster/dev/cpp/QGIS/src/core/symbology-ng/qgssymbol.cpp:386
#8  0x00007ffff529444b in QgsLinePatternFillSymbolLayer::startRender(QgsSymbolRenderContext&) (this=0x55555919dd10, context=...)
    at /home/webmaster/dev/cpp/QGIS/src/core/symbology-ng/qgsfillsymbollayer.cpp:2799
#9  0x00007ffff533f7b4 in QgsFillSymbolLayer::drawPreviewIcon(QgsSymbolRenderContext&, QSize) (this=0x55555919dd10, context=..., size=...)
    at /home/webmaster/dev/cpp/QGIS/src/core/symbology-ng/qgssymbollayer.cpp:639
#10 0x00007ffff5349f86 in QgsSymbolLayerUtils::symbolLayerPreviewIcon(QgsSymbolLayer*, QgsUnitTypes::RenderUnit, QSize, QgsMapUnitScale const&) (layer=0x55555919dd10, u=QgsUnitTypes::RenderMillimeters, size=..., scale=...) at /home/webmaster/dev/cpp/QGIS/src/core/symbology-ng/qgssymbollayerutils.cpp:667
#11 0x00007ffff658d497 in SymbolLayerItem::updatePreview() (this=0x555559253cf0) at /home/webmaster/dev/cpp/QGIS/src/gui/symbology-ng/qgssymbolselectordialog.cpp:150
#12 0x00007ffff658d3ce in SymbolLayerItem::setLayer(QgsSymbolLayer*) (this=0x555559253cf0, layer=0x55555919dd10) at /home/webmaster/dev/cpp/QGIS/src/gui/symbology-ng/qgssymbolselectordialog.cpp:135
#13 0x00007ffff658d2f4 in SymbolLayerItem::SymbolLayerItem(QgsSymbolLayer*) (this=0x555559253cf0, layer=0x55555919dd10)
    at /home/webmaster/dev/cpp/QGIS/src/gui/symbology-ng/qgssymbolselectordialog.cpp:122
#14 0x00007ffff6588b28 in QgsSymbolSelectorWidget::loadSymbol(QgsSymbol*, SymbolLayerItem*) (this=0x55555923d360, symbol=0x5555591a0440, parent=0x55555925a720)
    at /home/webmaster/dev/cpp/QGIS/src/gui/symbology-ng/qgssymbolselectordialog.cpp:321
#15 0x00007ffff65881b3 in QgsSymbolSelectorWidget::QgsSymbolSelectorWidget(QgsSymbol*, QgsStyle*, QgsVectorLayer const*, QWidget*) (this=0x55555923d360, symbol=0x5555591a0440, style=
    0x55555645f710, vl=0x5555591986a0, parent=0x0) at /home/webmaster/dev/cpp/QGIS/src/gui/symbology-ng/qgssymbolselectordialog.cpp:257
#16 0x00007ffff64f07b1 in QgsSingleSymbolRendererWidget::QgsSingleSymbolRendererWidget(QgsVectorLayer*, QgsStyle*, QgsFeatureRenderer*) (this=
    0x555558532290, layer=0x5555591986a0, style=0x55555645f710, renderer=0x555556cf8340) at /home/webmaster/dev/cpp/QGIS/src/gui/symbology-ng/qgssinglesymbolrendererwidget.cpp:57
#17 0x00007ffff64f05cb in QgsSingleSymbolRendererWidget::create(QgsVectorLayer*, QgsStyle*, QgsFeatureRenderer*) (layer=0x5555591986a0, style=0x55555645f710, renderer=0x555556cf8340)
    at /home/webmaster/dev/cpp/QGIS/src/gui/symbology-ng/qgssinglesymbolrendererwidget.cpp:32
#18 0x00007ffff530cb1e in QgsRendererMetadata::createRendererWidget(QgsVectorLayer*, QgsStyle*, QgsFeatureRenderer*) (this=0x555555c33d10, layer=0x5555591986a0, style=0x55555645f710, renderer=0x555556cf8340) at /home/webmaster/dev/cpp/QGIS/src/core/symbology-ng/qgsrendererregistry.h:148
#19 0x00007ffff64d1bcf in QgsRendererPropertiesDialog::rendererChanged() (this=0x5555591e6130) at /home/webmaster/dev/cpp/QGIS/src/gui/symbology-ng/qgsrendererpropertiesdialog.cpp:243
#20 0x00007ffff64d76a9 in QtPrivate::FunctorCall<QtPrivate::IndexesList<>, QtPrivate::List<>, void, void (QgsRendererPropertiesDialog::*)()>::call(void (QgsRendererPropertiesDialog::*)(), QgsRendererPropertiesDialog*, void**) (f=(void (QgsRendererPropertiesDialog::*)(QgsRendererPropertiesDialog * const)) 0x7ffff64d194a <QgsRendererPropertiesDialog::rendererChanged()>, o=0x5555591e6130, arg=0x7fffffffa050) at /usr/include/x86_64-linux-gnu/qt5/QtCore/qobjectdefs_impl.h:141
#21 0x00007ffff64d75a2 in QtPrivate::FunctionPointer<void (QgsRendererPropertiesDialog::*)()>::call<QtPrivate::List<>, void>(void (QgsRendererPropertiesDialog::*)(), QgsRendererPropertiesDialog*, void**) (f=(void (QgsRendererPropertiesDialog::*)(QgsRendererPropertiesDialog * const)) 0x7ffff64d194a <QgsRendererPropertiesDialog::rendererChanged()>, o=0x5555591e6130, arg=0x7fffffffa050)
    at /usr/include/x86_64-linux-gnu/qt5/QtCore/qobjectdefs_impl.h:160
#22 0x00007ffff64d6fa1 in QtPrivate::QSlotObject<void (QgsRendererPropertiesDialog::*)(), QtPrivate::List<>, void>::impl(int, QtPrivate::QSlotObjectBase*, QObject*, void**, bool*) (which=1, this_=0x555559244ef0, r=0x5555591e6130, a=0x7fffffffa050, ret=0x0) at /usr/include/x86_64-linux-gnu/qt5/QtCore/qobject_impl.h:120
#23 0x00007ffff3bc181e in QMetaObject::activate(QObject*, int, int, void**) () at /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#24 0x00007ffff496b471 in QComboBox::currentIndexChanged(int) () at /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#25 0x00007ffff496d8c1 in  () at /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#26 0x00007ffff497002d in  () at /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#27 0x00007ffff497024f in QComboBox::setCurrentIndex(int) () at /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#28 0x00007ffff64d2adc in QgsRendererPropertiesDialog::syncToLayer() (this=0x5555591e6130) at /home/webmaster/dev/cpp/QGIS/src/gui/symbology-ng/qgsrendererpropertiesdialog.cpp:378
#29 0x00007ffff64d0edb in QgsRendererPropertiesDialog::QgsRendererPropertiesDialog(QgsVectorLayer*, QgsStyle*, bool, QWidget*) (this=0x5555591e6130, layer=0x5555591986a0, style=0x55555645f710, embedded=true, parent=0x555556a82350) at /home/webmaster/dev/cpp/QGIS/src/gui/symbology-ng/qgsrendererpropertiesdialog.cpp:123
#30 0x00007ffff73e325c in QgsLayerStylingWidget::updateCurrentWidgetLayer() (this=0x555556a81d20) at /home/webmaster/dev/cpp/QGIS/src/app/qgslayerstylingwidget.cpp:354
#31 0x00007ffff73e8c5f in QtPrivate::FunctorCall<QtPrivate::IndexesList<>, QtPrivate::List<>, void, void (QgsLayerStylingWidget::*)()>::call(void (QgsLayerStylingWidget::*)(), QgsLayerStylingWidget*, void**) (f=(void (QgsLayerStylingWidget::*)(QgsLayerStylingWidget * const)) 0x7ffff73e2e98 <QgsLayerStylingWidget::updateCurrentWidgetLayer()>, o=0x555556a81d20, arg=0x7fffffffa770)

nyalldawson commented on Jul 11, 2017

@nyalldawson
CollaboratorAuthor

@nirvn looks like you've found another place where this crash could occur! Basically what my commit did is force these to be brought to our attention, rather then letting them hide away until random occurrences.

nirvn commented on Jul 11, 2017

@nirvn
Contributor

@nyalldawson , I've been able to come up with a small test project that crashes QGIS:
qgis-crash.zip

nirvn commented on Jul 11, 2017

@nirvn
Contributor

@nyalldawson , actually, no test project needed. Simply add a polygon dataset, and change its symbology to a line pattern symbol. boom.

Please sign in to comment.