Events after Object destruction
-
Hello!
I have a strange problem in a slow embedded system:
If I am fast enough, I can crash an application by double clicking a push button .
The reason behind this is, that in this application a window is closed as soon as someone is clicking the 'Ok' button. The window destruction is then taking place in the slot, that is linked to the 'pressed()' signal (the crash also occurs, if I use the 'clicked()' signal). What now happens is, that the first button press is shutting down the window doing a call to 'deleteLater(). While this is taking place, a the second button press is captured and placed in the event queue. I later get a message from the 'destroyed' signal, that the window is no longer existing but soon afterwards the application crashes, because the Event handler of QT is triggered by a mouse pressed event in the event queue. Because of this event he tries to access the object, which already has been deleted.
I already tried to place a 'QCoreApplication::removePostedEvents(sender()) into the slot that is called by the 'destroyed()' signal, but this did not make any difference.
The QT version I am using is 4.8.4. Has this maybe been solved in a later version?
Regards
Andreas
-
Hi jsulm,
this is already done.
The problem is, that the address is located in the QT event queue, where I do not have direct access to. Once the QT event handler finds an event there that says QPushButton with Address 0x1234 has been clicked, it tries to deliver this event to this push button instance, which is no longer there...
-
@anli
Purely guess here, I'm not an expert like @jsulm !If we're looking for a workaround:
in this application a window is closed as soon as someone is clicking the 'Ok' button. The window destruction is then taking place in the slot,
What code does it do to do this (closure/destruction)?
If you made it doQApplication::quit()
does that make any difference (seen elsewhere suggestion thatquit()
does stuff about flushing the event queue)? -
@anli
I think I mis-readapplication a window is closed
as
application window is closed
Just one missing "a"! I thought you were saying this was when the (main) application window is being closed, you are only talking about some other window somewhere?
-
@anli said in Events after Object destruction:
Yes, just one window should be closed, the rest of the application should continue to run
Please attach a stack trace.
-
@anli said in Events after Object destruction:
that the address is located in the QT event queue, where I do not have direct access to
What address do you mean?
How can it be located in the event loop?
Why don't you have access to it?You create window at some point in your app, right? Then you should have the pointer.
You should have something like this somewhere in your code:myWindow = new MyWindow();
-
Hello!
Sorry for my late reply. Here is the stack trace at the moment of the crash:0 QMetaObject::addGuard qobject.cpp 400 0xd65390 1 QPointer<QAbstractButton>::QPointer qpointer.h 60 0x774948 2 QAbstractButtonPrivate::emitPressed qabstractbutton.cpp 561 0x771df8 3 QAbstractButton::mousePressEvent qabstractbutton.cpp 1098 0x773198 4 QToolButton::mousePressEvent qtoolbutton.cpp 709 0x804310 5 QWidget::event qwidget.cpp 8371 0x39cc90 6 QAbstractButton::event qabstractbutton.cpp 1082 0x7730cc 7 QToolButton::event qtoolbutton.cpp 1160 0x80594c 8 QApplicationPrivate::notify_helper qapplication.cpp 4562 0x347e88 9 QApplication::notify qapplication.cpp 4105 0x346144 10 QCoreApplication::notifyInternal qcoreapplication.cpp 946 0xd4df34 11 QCoreApplication::sendSpontaneousEvent qcoreapplication.h 234 0x34a9b8 12 QETWidget::translateMouseEvent qapplication_qws.cpp 3528 0x3cb73c 13 QApplication::qwsProcessEvent qapplication_qws.cpp 2974 0x3c9660 14 QEventDispatcherQWS::processEvents qeventdispatcher_qws.cpp 119 0x3d2468 15 QEventLoop::processEvents qeventloop.cpp 149 0xd4b4fc 16 QEventLoop::exec qeventloop.cpp 200 0xd4b690 17 QCoreApplication::exec qcoreapplication.cpp 1218 0xd4e6f0 18 QApplication::exec qapplication.cpp 3823 0x344fac 19 main main.cpp 650 0x21900c ... <More>
And this is a simplified pseudo code of what is going on in the program:
... QWidget * m_pScreenW; QSignalMapper * m_pMapper; ... main() { .... connect( m_pUiState, SIGNAL( guiButtonPressed( const QString &, const QString & ) ), m_pSetupController, SLOT( slotButtonActivated( const QString &, const QString & ) ) ); .... } void raiseScreen(QObject* parent) { if ( m_pScreenW ) { qDebug() << "~~~DeleteLater of screen: " << m_pScreenW; m_pScreenW->deleteLater(); m_pScreenW = 0; } m_pScreenW = createNewScreenWithButtonsOnIt(parent); } QWidget* createNewScreenWithCloseButtonsOnIt(QObject* parent) { .... m_pScreenW = new QWidget(parent); m_pMapper = new QSignalMapper(m_pScreenW); .... if(screenContainsButton() { QToolButton pTB = new QToolButton(m_pScreenW); qDebug() << "~~+Creating toolbutton..." << pTB; connect(pTB, SIGNAL(destroyed()), this, SLOT(slotButtonDestroyed())); connect( p_pW, SIGNAL( pressed( ) ), m_pMapper, SLOT( map() ) ); } ... connect( m_pMapper, SIGNAL( mapped( const QString & ) ), this, SLOT( slotPreprocessGuiButton( const QString & ) ) ); connect( m_pWidget, SIGNAL(destroyed(QObject*)), this, SLOT(slotWindowDestroyed(QObject*))); .... } void dngApp_c::slotWindowDestroyed(QObject* o) { qDebug() << "~~~Window destroyed:" << o; } void layout_n::manager_c::slotButtonDestroyed(void) { qDebug() << "~~~Toolbutton destroyed" << sender(); } void dngApp_c::slotPreprocessGuiButton( const QString & p_strButton ) { emit guiButtonPressed( strButton, "GUI" ); } void ui_n::setupController_c::slotButtonActivated( const QString & p_strButtonId, const QString & p_strContext ) { .... else if ( p_strButtonId == strButtonIdAbortImmediately ) { //Do something time consuming here .... QTimer::singleShot( 0, this, SLOT( slotOpenNewWindow() ) ); } .... } void ui_n::setupController_c::slotOpenNewWindow( void ) { raiseScreen(0); }
In addition there is an event filter installed, that prduces the following output:
appEventFilter_c::appEventFilter_c( dngApp_c * p_pApp ) : QObject( p_pApp ) { .... p_pApp->installEventFilter( this ); } bool appEventFilter_c::eventFilter( QObject * p_pObject, QEvent * p_pEvent ) { if ( p_pObject && p_pEvent ) { switch ( p_pEvent->type() ) { .... case QEvent::MouseButtonPress: .... qDebug() << "---Pressed!!"; break; case QEvent::MouseButtonRelease: .... qDebug() << "---Released!!"; break; default: break; } } }
If I do a double press on the QToolButton, I get about the following output on the command line, the last line is the last output I get:
Line 38: ~~+Creating toolbutton... layout_n::toolButton_c(0x2365250) Line 39: ~~+Creating toolbutton... layout_n::toolButton_c(0x22bc008) Line 40: ~~+Creating toolbutton... layout_n::toolButton_c(0x22b5290) Line 41: ~~+Creating toolbutton... layout_n::toolButton_c(0x22bdf90) Line 43: ~~+Creating toolbutton... layout_n::toolButton_c(0x2432880) Line 44: ~~+Creating toolbutton... layout_n::toolButton_c(0x23796a0) Line 47: ~~+Creating toolbutton... layout_n::toolButton_c(0x2554b10) Line 48: ~~~Toolbutton destroyed QObject(0x22c91a0) Line 49: ~~~Toolbutton destroyed QObject(0x2412420) Line 50: ~~~Toolbutton destroyed QObject(0x24123c0) Line 51: ~~~Toolbutton destroyed QObject(0x2414a20) Line 52: ~~~Toolbutton destroyed QObject(0x241ff50) Line 53: ~~~Toolbutton destroyed QObject(0x241ff70) Line 54: ~~~Window destroyed: QObject(0x2354cf0, name = "6 34:03.188") Line 55: ~~~Toolbutton destroyed QObject(0x2554b10) Line 56: ~~~Window destroyed: QObject(0x2498580) Line 62: ~~+Creating toolbutton... layout_n::toolButton_c(0x254c038) Line 63: ~~+Creating toolbutton... layout_n::toolButton_c(0x254d010) Line 64: ~~~Toolbutton destroyed QObject(0x254c038) Line 72: ---Pressed!! Line 94: ---Released!! Line 95: --DeleteLater of screen: QWidget(0x235a2c0, name = "7 34:06.573") Line 96: ~~+Creating toolbutton... layout_n::toolButton_c(0x25bdf90) Line 97: ~~+Creating toolbutton... layout_n::toolButton_c(0x25bf7d0) Line 98: ~~+Creating toolbutton... layout_n::toolButton_c(0x25c73d0) Line 99: ~~+Creating toolbutton... layout_n::toolButton_c(0x25d1dc8) Line 101: ~~+Creating toolbutton... layout_n::toolButton_c(0x25d72d0) Line 106: ---Pressed!! Line 107: ~~~Toolbutton destroyed QObject(0x2365250) Line 108: ~~~Toolbutton destroyed QObject(0x22bc008) Line 109: ~~~Toolbutton destroyed QObject(0x22b5290) Line 110: ~~~Toolbutton destroyed QObject(0x22bdf90) Line 111: ~~~Toolbutton destroyed QObject(0x2432880) Line 112: ~~~Toolbutton destroyed QObject(0x23796a0) Line 113: ~~~Toolbutton destroyed QObject(0x254d010) Line 114: ~~~Window destroyed: QObject(0x231ec20) Line 115: ~~~# Qery: Trackdeletion PC Overlay Line 116: ~~~Window destroyed: QObject(0x235a2c0, name = "7 34:06.573")
If I now go up the stack trace, I find, at Level 4 "QToolButton::mousePressEvent" the following variable contents :
d @0x24b6020 QToolButtonPrivate e @0xbea566ec QMouseEvent opt QStyleOptionToolButton this "" @0x254d010 QToolButton
but the toolbutton with this address has already been deleted according to line 113, which leads the program to crash.
-
@anli said in Events after Object destruction:
What is the return result of this function
appEventFilter_c::eventFilter
and also what's the relation betweencreateNewScreenWithButtonsOnIt
andcreateNewScreenWithCloseButtonsOnIt
? -
@anli said in Events after Object destruction:
Because of this event he tries to access the object, which already has been deleted.
Hmm... if an object is deleted via
deleteLater()
, it should be removed from the event queue.the address is located in the QT event queue, where I do not have direct access to. Once the QT event handler finds an event there that says QPushButton with Address 0x1234 has been clicked, it tries to deliver this event to this push button instance, which is no longer there...
How is the button deleted? Also, are you using any threads in your application?
If you can't resolve your problem easily, consider replacing your window with a modal QDialog. This way, you don't need to delete the window manually, just let Qt take care of it.
The QT version I am using is 4.8.4. Has this maybe been solved in a later version?
Is it feasible to upgrade to Qt 4.8.7 at the very least?
-
Hello!
@kshegunov:
appEventFilter_c::eventFilter
always returns false so that the events are consumed by the event queue handler of QT, the relation between the two functions is, that there is a typo in my code example... They should both have the same name, I am sorry (the original names would have been too cryptic to have any meaning for you).@JKSH
As indicated in the code snipped above the object is deleted withdeleteLater()
and thedestroyed()
signal is linked with a slot, that prints aqDebug()
message stating that the button has already been deleted when the crash happens.
Yes, threads are used but not in combination with GUI related tasks. They are used for writing data to SD Card or communicating with ICs connected to the SBC. All data, that is exchanged between the threads is locked by Mutexes.
The software we are talking about has a free configurable design via style sheets without any window decoration. This is why the software does not use QDialogs. -
@anli From your logs, I suspect that it's just as you say: The deleted button doesn't get properly removed from the event queue.
I'm not sure what's the best way forward though. The first thing I'd recommend is to upgrade to Qt 4.8.7 and see if the issue exists there.
-
Hello JKSH,
in the meantime we already tried this. We also changed the hardware platform to a faster one to get an idea, if this is maybe the reason, but also with QT 4.8.7 we get there the effect.
It seems to me as if the QWS window list does not get updated in time...
-
@anli
You're still trying to sort out object deletion and signal/slot delivery etc., right?At this point if it were me, I would set up a new, standalone, minimal project, without worrying about "slow" or "embedded" etc., and just test what's going on in the simplest case, so that you understand. Having your full, complex, existing application code is just going to obscure whatever issue there is.
-
Might be a stupid workaround, but what happens when you, in your slot, set the PushButton to disabled, this should happe as the very first thing of course ?
-
For further information, I now attach a backtrace for the moment, when toolbutton is destroyed:
0 layout_n::manager_c::slotButtonDeleted layoutmanager.cpp 526 0x27eb70 1 layout_n::manager_c::qt_static_metacall moc_layoutmanager.cpp 243 0x28a4b4 2 QMetaObject::activate qobject.cpp 3540 0xd6c2f0 3 QObject::destroyed moc_qobject.cpp 149 0xd6dce8 4 QObject::~QObject qobject.cpp 843 0xd66c3c 5 QWidget::~QWidget qwidget.cpp 1705 0x38be4c 6 QAbstractButton::~QAbstractButton qabstractbutton.cpp 608 0x77284c 7 QToolButton::~QToolButton qtoolbutton.cpp 409 0x803c48 8 layout_n::toolButton_c::~toolButton_c layoutmanager.h 185 0x28b934 9 layout_n::toolButton_c::~toolButton_c layoutmanager.h 185 0x28b994 10 QObjectPrivate::deleteChildren qobject.cpp 1908 0xd68368 11 QWidget::~QWidget qwidget.cpp 1681 0x38bd90 12 QWidget::~QWidget qwidget.cpp 1705 0x38bec8 13 qDeleteInEventHandler qobject.cpp 4270 0xd6d858 14 QObject::event qobject.cpp 1175 0xd67384 15 QWidget::event qwidget.cpp 8846 0x39e564 16 QApplicationPrivate::notify_helper qapplication.cpp 4566 0x348428 17 QApplication::notify qapplication.cpp 4530 0x348260 18 QCoreApplication::notifyInternal qcoreapplication.cpp 947 0xd4e6b4 19 QCoreApplication::sendEvent qcoreapplication.h 231 0x34aee4 20 QCoreApplicationPrivate::sendPostedEvents qcoreapplication.cpp 1572 0xd4f950 21 QCoreApplication::sendPostedEvents qcoreapplication.cpp 1468 0xd4f548 22 QCoreApplication::sendPostedEvents qcoreapplication.h 236 0x3d2e68 23 QEventDispatcherQWS::flush qeventdispatcher_qws.cpp 164 0x3d2dbc 24 QCoreApplication::flush qcoreapplication.cpp 683 0xd4e0d0 25 QAbstractButton::mousePressEvent qabstractbutton.cpp 1101 0x773910 26 QToolButton::mousePressEvent qtoolbutton.cpp 710 0x804a90 27 QWidget::event qwidget.cpp 8371 0x39d230 28 QAbstractButton::event qabstractbutton.cpp 1085 0x77384c 29 QToolButton::event qtoolbutton.cpp 1162 0x8060cc 30 QApplicationPrivate::notify_helper qapplication.cpp 4566 0x348428 31 QApplication::notify qapplication.cpp 4108 0x3466e4 32 QCoreApplication::notifyInternal qcoreapplication.cpp 947 0xd4e6b4 33 QCoreApplication::sendSpontaneousEvent qcoreapplication.h 234 0x34af58 34 QETWidget::translateMouseEvent qapplication_qws.cpp 3539 0x3cbe08 35 QApplication::qwsProcessEvent qapplication_qws.cpp 2984 0x3c9d48 36 QEventDispatcherQWS::processEvents qeventdispatcher_qws.cpp 121 0x3d2b5c 37 QEventLoop::processEvents qeventloop.cpp 149 0xd4bc7c 38 QEventLoop::exec qeventloop.cpp 200 0xd4be10 39 QCoreApplication::exec qcoreapplication.cpp 1221 0xd4eec8 40 QApplication::exec qapplication.cpp 3823 0x34551c 41 main main.cpp 650 0x2192b4
There you can see, that the mouse button press is captured by the QWS system around line 34, beeing then forwarded to the respective button, which should paint the button as pressed (line 25) and performs a flush of the event queue to get the paint event processed, which in this case also finds the 'delete later' (line 13), that has been posted to the event queue by the previous mouse button press event and performs this deletion. After leaving the flush function, it will continue to operate on illegal pointer variables, because its own object has already been destroyed
-
@anli said in Events after Object destruction:
@JonB :
We tried it and currently do not get the problems there. We are currently trying to understand why.Alternatively, make a copy of your project and gradually simplify your code until the issue disappears.