SUMMARY Kontact (I use KMail, KOrganizer, KAgregator) often crashes on exit with the following messages: kf.xmlgui: 0x555555c63228 deleted without having been removed from the factory first. This will leak standalone popupmenus and could lead to crashes. kf.xmlgui: 0x555555d8b3e0 deleted without having been removed from the factory first. This will leak standalone popupmenus and could lead to crashes. kf.xmlgui: 0x555555d90d18 deleted without having been removed from the factory first. This will leak standalone popupmenus and could lead to crashes. kf.xmlgui: 0x555555bcaa58 deleted without having been removed from the factory first. This will leak standalone popupmenus and could lead to crashes. kf.xmlgui: 0x555555c36f68 deleted without having been removed from the factory first. This will leak standalone popupmenus and could lead to crashes. kf.xmlgui: 0x7fffdc00edb8 deleted without having been removed from the factory first. This will leak standalone popupmenus and could lead to crashes. ASSERT failure in KPIM::TransactionItemView: "Called object is not of the correct type (class destructor may have already run)", file /usr/include/x86_64-linux-gnu/qt6/QtCore/qobjectdefs_impl.h, line 129 Thread 1 "kontact" received signal SIGABRT, Aborted. STEPS TO REPRODUCE 1. Use Kontact for a while 2. Close it OBSERVED RESULT Crash EXPECTED RESULT No crash SOFTWARE/OS VERSIONS Confirmed in kontact 6.2.40 alpha (24.11.40) compiled from git, commit aaf08799507b586a1afbc672687f327a229a8f41. Crashes on exit have been present since about the switch to Plasma 6. Operating System: KDE neon 6.0 KDE Plasma Version: 6.1.3 KDE Frameworks Version: 6.4.0 Qt Version: 6.7.2 Kernel Version: 6.5.0-45-generic (64-bit) Graphics Platform: Wayland Processors: 8 × Intel® Core™ i5-10310U CPU @ 1.70GHz Memory: 15.3 Gio of RAM Graphics Processor: Mesa Intel® UHD Graphics ADDITIONAL INFORMATION Stack trace: #5 0x00007ffff68fdbca in qAbort() () at ./src/corelib/global/qglobal.cpp:161 #6 0x00007ffff68f875a in qt_message_fatal<QString&> (message=..., context=<optimized out>) at ./src/corelib/global/qlogging.cpp:2025 #7 qt_message(QtMsgType, const QMessageLogContext &, const char *, typedef __va_list_tag __va_list_tag *) (msgType=msgType@entry=QtFatalMsg, context=<optimized out>, msg=<optimized out>, ap=ap@entry=0x7fffffffc6b0) at ./src/corelib/global/qlogging.cpp:374 #8 0x00007ffff68fe56d in QMessageLogger::fatal(char const*, ...) const (this=<optimized out>, msg=<optimized out>) at ./src/corelib/global/qlogging.cpp:889 #9 0x00007ffff68c2ce2 in qt_assert_x(char const*, char const*, char const*, int) (where=<optimized out>, what=<optimized out>, file=<optimized out>, line=<optimized out>) at ./src/corelib/global/qassert.cpp:77 #10 0x00007ffff72cb9b6 in QtPrivate::assertObjectType<KPIM::TransactionItemView>(QObject*) (o=0x555555bfbb40) at /usr/include/x86_64-linux-gnu/qt6/QtCore/qobjectdefs_impl.h:129 #11 0x00007ffff72cb2e9 in QtPrivate::FunctorCall<QtPrivate::IndexesList<>, QtPrivate::List<>, void, void (KPIM::TransactionItemView::*)()>::call(void (KPIM::TransactionItemView::*)(), KPIM::TransactionItemView*, void**) (f=(void (KPIM::TransactionItemView::*)(class KPIM::TransactionItemView * const)) 0x7ffff72c2830 <KPIM::TransactionItemView::slotLayoutFirstItem()>, o=0x555555bfbb40, arg=0x7fffffffc9b0) at /usr/include/x86_64-linux-gnu/qt6/QtCore/qobjectdefs_impl.h:144 #12 0x00007ffff72ca6ac in QtPrivate::FunctionPointer<void (KPIM::TransactionItemView::*)()>::call<QtPrivate::List<>, void>(void (KPIM::TransactionItemView::*)(), KPIM::TransactionItemView*, void**) (f=(void (KPIM::TransactionItemView::*)(class KPIM::TransactionItemView * const)) 0x7ffff72c2830 <KPIM::TransactionItemView::slotLayoutFirstItem()>, o=0x555555bfbb40, arg=0x7fffffffc9b0) at /usr/include/x86_64-linux-gnu/qt6/QtCore/qobjectdefs_impl.h:182 #13 0x00007ffff72c9445 in QtPrivate::QCallableObject<void (KPIM::TransactionItemView::*)(), QtPrivate::List<>, void>::impl(int, QtPrivate::QSlotObjectBase*, QObject*, void**, bool*) (which=1, this_=0x55555623c250, r=0x555555bfbb40, a=0x7fffffffc9b0, ret=0x0) at /usr/include/x86_64-linux-gnu/qt6/QtCore/qobjectdefs_impl.h:553 #14 0x00007ffff686381b in QtPrivate::QSlotObjectBase::call(QObject*, void**) (a=0x7fffffffc9b0, r=0x555555bfbb40, this=<optimized out>, this=<optimized out>, r=<optimized out>, a=<optimized out>) at ./src/corelib/kernel/qobjectdefs_impl.h:469 #15 doActivate<false>(QObject*, int, void**) (sender=0x555558d30020, signal_index=0, argv=0x7fffffffc9b0) at ./src/corelib/kernel/qobject.cpp:4086 #16 0x00007ffff680e6d3 in QObject::destroyed(QObject*) (this=this@entry=0x555558d30020, _t1=<optimized out>, _t1@entry=0x555558d30020) at ./obj-x86_64-linux-gnu/src/corelib/kernel/moc_qobject.cpp:229 #17 0x00007ffff7a3248b in QWidget::~QWidget() (this=0x555558d30020, this=<optimized out>) at ./src/widgets/kernel/qwidget.cpp:1539 #18 0x00007ffff72c33bd in KPIM::TransactionItem::~TransactionItem() (this=0x555558d30020, __in_chrg=<optimized out>) at /home/louis/Personal/kde6/src/libkdepim/src/progresswidget/progressdialog.cpp:260 #19 0x00007ffff72c33e6 in KPIM::TransactionItem::~TransactionItem() (this=0x555558d30020, __in_chrg=<optimized out>) at /home/louis/Personal/kde6/src/libkdepim/src/progresswidget/progressdialog.cpp:260 #20 0x00007ffff67f8d7a in QObjectPrivate::deleteChildren() (this=this@entry=0x555555d3f0c0) at ./src/corelib/kernel/qobject.cpp:2222 #21 0x00007ffff7a32498 in QWidget::~QWidget() (this=0x555555d3f090, this=<optimized out>) at ./src/widgets/kernel/qwidget.cpp:1559 #22 0x00007ffff7a324dd in QWidget::~QWidget() (this=0x555555d3f090, this=<optimized out>) at ./src/widgets/kernel/qwidget.cpp:1585 #23 0x00007ffff67f8d7a in QObjectPrivate::deleteChildren() (this=this@entry=0x5555559a76e0) at ./src/corelib/kernel/qobject.cpp:2222 #24 0x00007ffff7a32498 in QWidget::~QWidget() (this=0x555555b96460, this=<optimized out>) at ./src/widgets/kernel/qwidget.cpp:1559 #25 0x00007ffff7a324dd in QWidget::~QWidget() (this=0x555555b96460, this=<optimized out>) at ./src/widgets/kernel/qwidget.cpp:1585 #26 0x00007ffff67f8d7a in QObjectPrivate::deleteChildren() (this=this@entry=0x5555559d5280) at ./src/corelib/kernel/qobject.cpp:2222 #27 0x00007ffff7a32498 in QWidget::~QWidget() (this=0x555555bfbb40, this=<optimized out>) at ./src/widgets/kernel/qwidget.cpp:1559 #28 0x00007ffff72c24b5 in KPIM::TransactionItemView::~TransactionItemView() (this=0x555555bfbb40, __in_chrg=<optimized out>) at /home/louis/Personal/kde6/src/libkdepim/src/progresswidget/progressdialog.cpp:126 #29 0x00007ffff72c24de in KPIM::TransactionItemView::~TransactionItemView() (this=0x555555bfbb40, __in_chrg=<optimized out>) at /home/louis/Personal/kde6/src/libkdepim/src/progresswidget/progressdialog.cpp:126 #30 0x00007ffff67f8d7a in QObjectPrivate::deleteChildren() (this=this@entry=0x555555a80a60) at ./src/corelib/kernel/qobject.cpp:2222 #31 0x00007ffff7a32498 in QWidget::~QWidget() (this=0x555555de8dd0, this=<optimized out>) at ./src/widgets/kernel/qwidget.cpp:1559 #32 0x00007ffff72c1fb4 in KPIM::OverlayWidget::~OverlayWidget() (this=0x555555de8dd0, __in_chrg=<optimized out>) at /home/louis/Personal/kde6/src/libkdepim/src/progresswidget/progressdialog.cpp:49 #33 0x00007ffff72c3c70 in KPIM::ProgressDialog::~ProgressDialog() (this=0x555555de8dd0, __in_chrg=<optimized out>) at /home/louis/Personal/kde6/src/libkdepim/src/progresswidget/progressdialog.cpp:364 #34 0x00007ffff72c3c9a in KPIM::ProgressDialog::~ProgressDialog() (this=0x555555de8dd0, __in_chrg=<optimized out>) at /home/louis/Personal/kde6/src/libkdepim/src/progresswidget/progressdialog.cpp:364 #35 0x00007ffff67f8d7a in QObjectPrivate::deleteChildren() (this=this@entry=0x5555558e1860) at ./src/corelib/kernel/qobject.cpp:2222 #36 0x00007ffff7a32498 in QWidget::~QWidget() (this=0x5555555f6ee0, this=<optimized out>) at ./src/widgets/kernel/qwidget.cpp:1559 #37 0x00007ffff7ef1393 in KontactInterface::Core::~Core() (this=0x5555555f6ee0, __vtt_parm=0x7ffff7fb63e8 <VTT for Kontact::MainWindow+8>, __in_chrg=<optimized out>) at /home/louis/Personal/kde6/src/kontactinterface/src/core.cpp:56 #38 0x00007ffff7f44659 in Kontact::MainWindow::~MainWindow() (this=0x5555555f6ee0, __in_chrg=<optimized out>, __vtt_parm=<optimized out>) at /home/louis/Personal/kde6/src/kontact/src/mainwindow.cpp:214 #39 0x00007ffff7f44704 in Kontact::MainWindow::~MainWindow() (this=0x5555555f6ee0, __in_chrg=<optimized out>, __vtt_parm=<optimized out>) at /home/louis/Personal/kde6/src/kontact/src/mainwindow.cpp:214 #40 0x00007ffff67fa283 in QObject::event(QEvent*) (this=0x5555555f6ee0, e=0x555558d0e280) at ./src/corelib/kernel/qobject.cpp:1437 #41 0x00007ffff7e4b0d3 in KXmlGuiWindow::event(QEvent*) (this=0x5555555f6ee0, ev=0x555558d0e280) at ./src/kxmlguiwindow.cpp:221 #42 0x00007ffff7a0a1ab in QApplicationPrivate::notify_helper(QObject*, QEvent*) (this=<optimized out>, receiver=0x5555555f6ee0, e=0x555558d0e280) at ./src/widgets/kernel/qapplication.cpp:3287 #43 0x00007ffff68a1dd8 in QCoreApplication::notifyInternal2(QObject*, QEvent*) (receiver=0x5555555f6ee0, event=event@entry=0x555558d0e280) at ./src/corelib/kernel/qcoreapplication.cpp:1142 #44 0x00007ffff68a1e1d in QCoreApplication::sendEvent(QObject*, QEvent*) (receiver=<optimized out>, event=event@entry=0x555558d0e280) at ./src/corelib/kernel/qcoreapplication.cpp:1583 #45 0x00007ffff68a2590 in QCoreApplicationPrivate::sendPostedEvents(QObject*, int, QThreadData*) (receiver=0x0, event_type=0, data=0x555555593660) at ./src/corelib/kernel/qcoreapplication.cpp:1940 #46 0x00007ffff66641a7 in postEventSourceDispatch(GSource*, GSourceFunc, gpointer) (s=0x555555657810) at ./src/corelib/kernel/qeventdispatcher_glib.cpp:244 #47 0x00007fffe89c0d3b in g_main_context_dispatch () at /lib/x86_64-linux-gnu/libglib-2.0.so.0 #48 0x00007fffe8a162b8 in () at /lib/x86_64-linux-gnu/libglib-2.0.so.0 #49 0x00007fffe89be3e3 in g_main_context_iteration () at /lib/x86_64-linux-gnu/libglib-2.0.so.0 #50 0x00007ffff6662700 in QEventDispatcherGlib::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) (this=0x5555555c3e40, flags=...) at ./src/corelib/kernel/qeventdispatcher_glib.cpp:394 #51 0x00007ffff68a3feb in QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) (this=this@entry=0x7fffffffd4a0, flags=..., flags@entry=...) at ./src/corelib/global/qflags.h:34 #52 0x00007ffff68a5c2c in QCoreApplication::exec() () at ./src/corelib/global/qflags.h:74 #53 0x0000555555559db9 in main(int, char**) (argc=1, argv=0x7fffffffd8e8) at /home/louis/Personal/kde6/src/kontact/src/main.cpp:225
Still present in 6.2.1. Steps to reproduce: 1. Start Kontact (kmail view) 2. Run "akonadictl restart" from the shell 3. Quit Kontact 4. Kontact aborts I narrowed this crash down to a bug in KPIM::ProgressDialog: 1. ProgressDialog has a child TransactionItemView object 2. In ProgressDialog::slotTransactionCompleted(), a TransactionItem's destroyed() signal is connected to TransactionItemView::slotLayoutFirstItem on the view 3. The view owns the item (recursively through multiple objects) 4. When the view is deleted, the view's destructor runs first 5. At this point the object is no longer a valid TransactionItemView 6. The QObject destructor runs and deletes children 7. The TransactionItem gets deleted 8. TransactionItem emits its destroyed() signal 9. TransactionItemView::slotLayoutFirstItem gets called on the now-deleted view 10. Qt asserts I'm not sure how to fix. This might have worked only by chance in the past (if Qt wouldn't detect it it would be UB).
Great analysis. As for a possible fix: TransactionItem could emit an itemDestroyed() signal (to be added), so that the code connected to that sees a full TransactionItem instance rather than a partially deleted QObject.
Oh, you said TransactionItemView itself is down to a QObject. Then it needs to disconnect() the connect to the destroyed signal. This is likely a regression coming from the port from SIGNAL()/SLOT() to &Class::slot syntax. The latter syntax creates this kind of bug because the connection remains valid until full destruction, while the SIGNAL/SLOT solution was based on virtual methods so no slot was called in a partially destroyed receiver. This means storing the return value of the connect() statement into a QMetaObject::Connection member variable, and using it to disconnect in the destructor.
A possibly relevant merge request was started @ https://invent.kde.org/pim/libkdepim/-/merge_requests/27
Git commit 15099be5c7b1ca365600f2a3d7550bac0bde0e1a by David Faure. Committed on 24/12/2024 at 16:18. Pushed by dfaure into branch 'master'. Fix crash on exit if mailcheck is happening Disconnect to avoid calling into a partially-deleted TransactionItemView Downside: these connections accumulate over time... M +12 -2 src/progresswidget/progressdialog.cpp M +1 -0 src/progresswidget/progressdialog.h https://invent.kde.org/pim/libkdepim/-/commit/15099be5c7b1ca365600f2a3d7550bac0bde0e1a
Git commit e7435bc6d80b5a9c170d209928586c5295e646b1 by David Faure. Committed on 26/12/2024 at 12:22. Pushed by dfaure into branch 'release/24.12'. Fix crash on exit if mailcheck is happening Disconnect to avoid calling into a partially-deleted TransactionItemView Downside: these connections accumulate over time... M +12 -2 src/progresswidget/progressdialog.cpp M +1 -0 src/progresswidget/progressdialog.h https://invent.kde.org/pim/libkdepim/-/commit/e7435bc6d80b5a9c170d209928586c5295e646b1