在缓慢的嵌入式系统中,我遇到了一个奇怪的问题:
如果我足够快,我可以通过双击按钮使应用程序崩溃。
其背后的原因是,在该应用程序中,只要有人单击“确定”按钮,就会关闭一个窗口。然后,在与“ pressed()”信号链接的插槽中发生窗口破坏(如果使用“ clicked()”信号,也会发生崩溃)。现在发生的是,第一次按下按钮正在关闭窗口,并调用'deleteLater()。进行此操作时,将捕获第二次按钮按下并将其放置在事件队列中。稍后我从“销毁”信号中得到一条消息,该窗口不再存在,但不久之后应用程序崩溃,因为QT的事件处理程序是由事件队列中的鼠标按下事件触发的。由于此事件,他尝试访问已被删除的对象。
我已经尝试过将'QCoreApplication :: removePostedEvents(sender())放入'destroyed()'信号所调用的插槽中,但这没有任何区别。
我使用的QT版本是4.8.4。这可能在以后的版本中解决了吗?
这是崩溃时的堆栈跟踪:
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
这是程序中正在发生的事情的简化的伪代码:
...
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* createNewScreenWithButtonsOnIt(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);
}
此外,还安装了事件过滤器,以获取有关事件队列的其他信息:
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;
}
}
}
如果我双击QToolButton,则会在命令行中获得以下输出,最后一行是我获得的最后输出:
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: ~~~# Query: Trackdeletion PC Overlay
Line 116: ~~~Window destroyed: QObject(0x235a2c0, name = "7 34:06.573")
如果我现在进行堆栈跟踪,可以在第4级“ QToolButton :: mousePressEvent”处找到以下变量内容:
d @0x24b6020 QToolButtonPrivate
e @0xbea566ec QMouseEvent
opt QStyleOptionToolButton
this "" @0x254d010 QToolButton
但是根据第113行已经删除了具有该地址的工具按钮,这导致程序崩溃。
答案 0 :(得分:0)
有关更多信息,我现在在工具按钮被销毁的瞬间添加回溯记录:
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
您可以看到QWS系统在第34行附近捕获到了鼠标按键,然后蜂鸣到相应的按钮,按键应将该按钮绘制为按下状态(第25行)并刷新事件队列为了处理绘制事件,在这种情况下,它还会找到“上一步删除”(第13行),该事件已由上一个鼠标按键事件发布到事件队列中并执行此删除操作。退出flush函数后,它将继续对非法的指针变量进行操作,因为其自身的对象已被破坏