https://bugs.kde.org/show_bug.cgi?id=516937

            Bug ID: 516937
           Summary: plasmashell crashes at startup: dangling pointer in
                    m_waitingPanels causes SIGSEGV in isScreenUiReady()
    Classification: Plasma
           Product: plasmashell
      Version First master
       Reported In:
          Platform: NixOS
                OS: Linux
            Status: REPORTED
          Severity: crash
          Priority: NOR
         Component: Startup process
          Assignee: [email protected]
          Reporter: [email protected]
                CC: [email protected]
  Target Milestone: 1.0

Created attachment 190251
  --> https://bugs.kde.org/attachment.cgi?id=190251&action=edit
Patch attached.

plasmashell crashes at startup on multi-monitor setups. The crash is
100% reproducible on cold login and affects at least 6.6.0 and 6.6.1.

== Crash trace (Thread 1) ==

#4  Plasma::Containment::lastScreen() const  [libPlasma.so.7]
#5  ShellCorona::isScreenUiReady(int)
#6  ShellCorona::checkAllDesktopsUiReady()
#7  void doActivate<false>(QObject*, int, void**)  [libQt6Core]
#8  Plasma::Containment::uiReadyChanged(bool)
#9  Plasma::AppletPrivate::setUiReady()
#10 Plasma::Applet::flushPendingConstraintsEvents()
#11 QObject::event(QEvent*)
#12 ... QTimerInfoList::activateTimers() ...

== Root cause ==

m_waitingPanels holds raw Plasma::Containment* pointers. Between
load() populating the list and createWaitingPanels() running (after a
250 ms timer), those pointers have no lifetime guard.

checkAllDesktopsUiReady() can fire before the timer via uiReadyChanged
from a desktop applet. It calls isScreenUiReady(), which iterates
m_waitingPanels and calls cont->lastScreen() on each entry. If any
containment was freed in the meantime, the qobject_cast<Containment*>
(parent()) inside lastScreen() dereferences a corrupted vtable → SIGSEGV
(observed PC = 0x7).

The old early guard (connecting QObject::destroyed in the constructor for
panel-type containments) was removed in commit 086ff5d8, which created
this regression. That commit reasoned that createWaitingPanels() already
connects destroyed — but it does so only after successfully creating a
PanelView, which is too late.

Commit 00bd19ec introduced the vulnerable window; 086ff5d8 removed the
guard that covered it.

== Fix ==

Change m_waitingPanels from QList<Plasma::Containment*> to
QList<QPointer<Plasma::Containment>>. QPointer auto-nulls when the
object is destroyed, eliminating the dangling-pointer window entirely:

- createWaitingPanels() calls removeAll(nullptr) at entry to purge any
  freed containments, and no longer needs to connect destroyed.
- panelContainmentDestroyed() no longer needs a m_waitingPanels branch;
  it returns early if the containment has no panel view.
- isScreenUiReady() null-checks each QPointer before dereferencing.

Patch attached.

== Environment ==
- KDE Plasma 6.6.1, NixOS, dual-monitor (Wayland)
- Reproducible on every cold login
- GPU: irrelevant (crash is in Qt signal dispatch, not rendering)

-- 
You are receiving this mail because:
You are watching all bug changes.

Reply via email to