Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

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


  • Lifetime Qt Champion

    @anli After calling deleteLater() assign nullptr to the pointer variable.
    In that slot check the pointer:

    if (myWindow) {
        myWindow->deleteLater();
        myWindow = nullptr;
    }
    


  • 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 do QApplication::quit() does that make any difference (seen elsewhere suggestion that quit() does stuff about flushing the event queue)?



  • Hi JonB!

    The QApplication::quit function halts the event queue, which I definitely do not want, because the application should continue to run.



  • @anli
    I think I mis-read

    application 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?



  • Yes, just one window should be closed, the rest of the application should continue to run


  • Moderators

    @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.


  • Lifetime Qt Champion

    @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.


  • Moderators

    @anli said in Events after Object destruction:

    What is the return result of this function appEventFilter_c::eventFilter and also what's the relation between createNewScreenWithButtonsOnIt and createNewScreenWithCloseButtonsOnIt?


  • Moderators

    @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 with deleteLater() and the destroyed() signal is linked with a slot, that prints a qDebug() 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.


  • Moderators

    @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.


  • Moderators

    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 ?



  • @JonB :
    We tried it and currently do not get the problems there. We are currently trying to understand why.

    @J-Hilk :
    We also tried this, but the second event got fired, before the button is disabled...



  • 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


  • Moderators

    @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.


  • Moderators

    @anli said in Events after Object destruction:

    We also tried this, but the second event got fired, before the button is disabled...

    mmh, I'll like to throw in a new idea.
    You should check, if your connection between button and slot is unique. If you called connect somewhere twice, than this could lead to the race condition.



  • @JKSH :
    Good idea! I will try this next.

    @J-Hilk :
    I have checked the code for hat, but did not find any issues.
    The problem is not always there, it just occurs, if I make several clicks on the same button while the software is busy doing some work.


Log in to reply