PDA

View Full Version : Deleting QGraphicsItem with QGraphicsEffect leads to segfault



tfm
26th January 2017, 12:24
The following program paints a red background. Pressing the left mouse button paints a white rectangle onto it. The rectangle has a child rectangle and a QGraphicsDropShadowEffect. (QGraphicsOpacityEffect and QGraphicsColorizeEffect also lead to the problem, but less frequently.)

Pressing the right mouse button removes the white rectangle.

Sometimes when removing the rectangle it causes a segmentation fault.

This does not happen if the QGraphicsDropShadowEffect is not applied. It also does not happen when there either is no child item in 'MyRect' or the background is ommited.

(When searching for this issue, I found several hints that a segfault like this could be related to changing the 'boundingRect()' of an item without calling 'prepareGeometryChange()'.)

I am really at a loss here. This is part of a bigger project and I boiled it down to the following example. This is on Debian, Qt 5.7.1+dfsg-3, GCC 6.2.1-5.

Main.cc:

#include<QApplication>
#include<QGraphicsView>
#include<QGraphicsScene>
#include<QGraphicsSceneMouseEvent>
#include<QGraphicsRectItem>
#include<QGraphicsDropShadowEffect>
#include<QScreen>

class MyRect: public QGraphicsRectItem
{
public:
MyRect(QGraphicsItem* parent = nullptr):
QGraphicsRectItem{QRectF{0.0f, 0.0f, 100.0f, 100.0f}, parent}
{
setPen(QPen{Qt::white});
setBrush(QBrush{Qt::white, Qt::SolidPattern});
new QGraphicsRectItem{this};
}
};

QGraphicsView* view=nullptr;
QGraphicsRectItem* background=nullptr;
MyRect* global_rect=nullptr;

void
createRect(QGraphicsScene* scene)
{
if (global_rect==nullptr)
{
global_rect=new MyRect{};
auto shadow=new QGraphicsDropShadowEffect{};
shadow->setBlurRadius(15.0f);
global_rect->setGraphicsEffect(shadow);
scene->addItem(global_rect);
global_rect->setPos(global_rect->mapToParent(global_rect->mapFromScene(view->mapToScene(view->mapFromGlobal(QCursor::pos())))));
}
}

void
destroyRect(QGraphicsScene* scene)
{
if (global_rect!=nullptr)
{
scene->removeItem(global_rect);
delete global_rect;
global_rect=nullptr;
}
}

class MyScene: public QGraphicsScene
{
public:
void mouseReleaseEvent(QGraphicsSceneMouseEvent* me) override
{
if (me->button()==Qt::LeftButton)
{
createRect(this);
}
else if (me->button()==Qt::RightButton)
{
destroyRect(this);
}
else
{
QGraphicsScene::mouseReleaseEvent(me);
}
}
};

int
main(int argc, char** argv)
{
QApplication qapp{argc, argv};

view=new QGraphicsView{};
MyScene scene;

QRect rect=QGuiApplication::primaryScreen()->geometry();
scene.setSceneRect(0.0f, 0.0f, rect.width(), rect.height());
view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff) ;
view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOf f);
view->setFrameShape(QFrame::NoFrame);
view->setBackgroundBrush(QBrush(Qt::black, Qt::SolidPattern));
view->setScene(&scene);
view->showFullScreen();

background=new QGraphicsRectItem{0.0f, 0.0f, 500.0f, 500.0f};
background->setPen(QPen{Qt::white});
background->setBrush(QBrush{Qt::red, Qt::SolidPattern});
scene.addItem(background);

return qapp.exec();
}

Compiler call:



g++ --std=c++14 -fPIC -Wall -Woverloaded-virtual -Werror -pedantic -g -O0 -fPIC -I/usr/include/x86_64-linux-gnu/qt5/QtGui -I/usr/include/x86_64-linux-gnu/qt5/QtWidgets -I/usr/include/x86_64-linux-gnu/qt5/QtCore -I/usr/include/x86_64-linux-gnu/qt5 -o test Main.cc -lQt5Gui -lQt5Core -lQt5Widgets


Backtrace:



#0 0x00007ffff71a1b84 in QGraphicsItem::parentItem() const () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#1 0x00007ffff71a1bab in QGraphicsItem::topLevelItem() const () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#2 0x00007ffff71eab6e in ?? () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#3 0x00007ffff71e9ba6 in ?? () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#4 0x00007ffff71e9bfa in ?? () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#5 0x00007ffff71e9bfa in ?? () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#6 0x00007ffff71e9ba6 in ?? () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#7 0x00007ffff71e9c83 in ?? () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#8 0x00007ffff71ecd3c in ?? () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#9 0x00007ffff71ed007 in ?? () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#10 0x00007ffff71dfc0d in ?? () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#11 0x00007ffff7201aaa in QGraphicsView::paintEvent(QPaintEvent*) () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#12 0x00007ffff6f0f218 in QWidget::event(QEvent*) () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#13 0x00007ffff6ff799e in QFrame::event(QEvent*) () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#14 0x00007ffff72005bb in QGraphicsView::viewportEvent(QEvent*) () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#15 0x00007ffff76506f1 in QCoreApplicationPrivate::sendThroughObjectEventFil ters(QObject*, QEvent*) () from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#16 0x00007ffff6ec7b05 in QApplicationPrivate::notify_helper(QObject*, QEvent*) () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#17 0x00007ffff6ecf2e1 in QApplication::notify(QObject*, QEvent*) () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#18 0x00007ffff7650990 in QCoreApplication::notifyInternal2(QObject*, QEvent*) () from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#19 0x00007ffff6f07f7a in QWidgetPrivate::sendPaintEvent(QRegion const&) () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#20 0x00007ffff6f085e6 in QWidgetPrivate::drawWidget(QPaintDevice*, QRegion const&, QPoint const&, int, QPainter*, QWidgetBackingStore*) ()
from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#21 0x00007ffff6ed7ebe in ?? () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#22 0x00007ffff6ed80e7 in ?? () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#23 0x00007ffff6ef6f2f in QWidgetPrivate::syncBackingStore() () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#24 0x00007ffff6f0f2e8 in QWidget::event(QEvent*) () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#25 0x00007ffff6ff799e in QFrame::event(QEvent*) () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#26 0x00007ffff7080d83 in QAbstractScrollArea::event(QEvent*) () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#27 0x00007ffff6ec7b2c in QApplicationPrivate::notify_helper(QObject*, QEvent*) () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#28 0x00007ffff6ecf2e1 in QApplication::notify(QObject*, QEvent*) () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#29 0x00007ffff7650990 in QCoreApplication::notifyInternal2(QObject*, QEvent*) () from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#30 0x00007ffff765311d in QCoreApplicationPrivate::sendPostedEvents(QObject* , int, QThreadData*) () from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#31 0x00007ffff71d1c32 in ?? () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#32 0x00007ffff71d74a9 in ?? () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#33 0x00007ffff767d449 in QObject::event(QEvent*) () from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#34 0x00007ffff71e407b in QGraphicsScene::event(QEvent*) () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#35 0x00007ffff6ec7b2c in QApplicationPrivate::notify_helper(QObject*, QEvent*) () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#36 0x00007ffff6ecf2e1 in QApplication::notify(QObject*, QEvent*) () from /usr/lib/x86_64-linux-gnu/libQt5Widgets.so.5
#37 0x00007ffff7650990 in QCoreApplication::notifyInternal2(QObject*, QEvent*) () from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#38 0x00007ffff765311d in QCoreApplicationPrivate::sendPostedEvents(QObject* , int, QThreadData*) () from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#39 0x00007ffff76a4bf3 in ?? () from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#40 0x00007ffff446e7f7 in g_main_context_dispatch () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
#41 0x00007ffff446ea60 in ?? () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
#42 0x00007ffff446eb0c in g_main_context_iteration () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
#43 0x00007ffff76a4fff in QEventDispatcherGlib::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) () from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#44 0x00007ffff764e97a in QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) () from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#45 0x00007ffff76570ec in QCoreApplication::exec() () from /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
#46 0x0000555555557b10 in main (argc=1, argv=0x7fffffffe5b8) at Main.cc:92

d_stranz
26th January 2017, 20:25
This is some of the strangest code I have seen in a while. Not only are you using global variables for some unknown reason, you are doing things like (in line 17 of Main.cc) creating a new QGraphicsRectItem without assigning the resulting pointer to anything.

You have standalone methods to modify the scene which should be class methods of MyScene, not standalone. Your view is a global pointer instead of being declared a stack variable in main() like your MyScene variable is. The "global_rect" and "background" global variables shouldn't be global but should probably be members of the MyScene class.

I'd suggest you refactor your code to remove all the strange things and maybe your crashes will clear up with them.

tfm
26th January 2017, 21:53
I can't seem to find the button to edit my post. I have rewritten the code but the problem persists.



#include<QApplication>
#include<QGraphicsView>
#include<QGraphicsScene>
#include<QGraphicsSceneMouseEvent>
#include<QGraphicsRectItem>
#include<QGraphicsDropShadowEffect>
#include<QScreen>

class MyRect: public QGraphicsRectItem
{
public:
MyRect(QGraphicsItem* parent = nullptr):
QGraphicsRectItem{QRectF{0.0f, 0.0f, 100.0f, 100.0f}, parent}
{
setPen(QPen{Qt::white});
setBrush(QBrush{Qt::white, Qt::SolidPattern});
my_child_=new QGraphicsRectItem{this};
}

private:
QGraphicsRectItem* my_child_=nullptr;
};

class MyScene: public QGraphicsScene
{
public:
MyScene()
{
background_=new QGraphicsRectItem{0.0f, 0.0f, 500.0f, 500.0f};
background_->setPen(QPen{Qt::white});
background_->setBrush(QBrush{Qt::red, Qt::SolidPattern});
addItem(background_);
}

void mouseReleaseEvent(QGraphicsSceneMouseEvent* me) override
{
if (me->button()==Qt::LeftButton)
{
if (my_rect_==nullptr)
{
my_rect_=new MyRect{};
shadow_=new QGraphicsDropShadowEffect{};
shadow_->setBlurRadius(15.0f);
my_rect_->setGraphicsEffect(shadow_);
addItem(my_rect_);
my_rect_->setPos(me->scenePos());
}
}
else if (me->button()==Qt::RightButton)
{
if (my_rect_!=nullptr)
{
removeItem(my_rect_);
my_rect_->setGraphicsEffect(0);
shadow_=nullptr;
delete my_rect_;
my_rect_=nullptr;
}
}
else
{
QGraphicsScene::mouseReleaseEvent(me);
}
}

private:
QGraphicsRectItem* background_=nullptr;
MyRect* my_rect_=nullptr;
QGraphicsDropShadowEffect* shadow_=nullptr;
};

int
main(int argc, char** argv)
{
QApplication qapp{argc, argv};

QGraphicsView view;
MyScene scene;

QRect rect=QGuiApplication::primaryScreen()->geometry();
scene.setSceneRect(0.0f, 0.0f, rect.width(), rect.height());
view.setVerticalScrollBarPolicy(Qt::ScrollBarAlway sOff);
view.setHorizontalScrollBarPolicy(Qt::ScrollBarAlw aysOff);
view.setFrameShape(QFrame::NoFrame);
view.setBackgroundBrush(QBrush(Qt::black, Qt::SolidPattern));
view.setScene(&scene);
view.showFullScreen();

return qapp.exec();
}

d_stranz
26th January 2017, 23:30
I can't really see anywhere in this code that would cause a crash. What happens if you start the program and then immediately exit? (In other words, don't click the mouse in the view).

tfm
27th January 2017, 00:53
It is probably a bug in Qt. A possibly explanation and a workaround can be found here:

https://forum.qt.io/topic/75510/deleting-qgraphicsitem-with-qgraphicseffect-leads-to-segfault

d_stranz
28th January 2017, 01:18
Hmmm. It is considered to be pretty rude to cross-post the same question to different forums. Had you not given that link, probably very few people here would know. So, we're wasting our time trying to find an answer to your problem here at the same time that you and others are working on the same thing somewhere else.

tfm
28th January 2017, 14:31
I'm sorry, I didn't mean to be rude. Thank you for your answer that you see no problem in my code.

But I cannot see how anyone's time has been wasted. Your time would have been wasted if I had continued the topic here and not posted the link that it has been resolved.

Also there wasn't really an issue to "work on". My question was whether or not my code is correct. I'm grateful for your assessment, that you see nothing wrong; others went further and stated quite clearly that the code is correct and the error must be in Qt and provided a workaround from their experience, which I shared with you.