reference: https://discuss.kde.org/t/plasmaloginmanager-blank-screen-only-on-first-cold-boot/46087/2 ``` TITLE plasma-login-greeter: SIGSEGV in QWindow::screen() via dangling QWindowPrivate pointer when Wayland compositor replaces pending screen output during startup COMPONENT plasma-login-manager VERSION 6.6.4-1.fc43 SEVERITY Critical -- process terminates on every cold boot --- ENVIRONMENT OS: Fedora 43, x86_64 (kernel 6.19.11-200.fc43.x86_64) Package: plasma-login-manager-6.6.4-1.fc43.x86_64 Binary: /usr/libexec/plasma-login-greeter Build ID: ec6b236da37d731156d601f1f4d19fae54a14ffb Qt: 6.10.3 (libQt6Gui.so.6, libQt6WaylandClient.so.6) Session: Wayland Display: Single monitor User: plasmalogin (UID 967, GID 967) Unit: user@967.service -> user unit plasma-login.service --- OBSERVABLE BEHAVIOR On every cold boot, plasma-login-greeter terminates with SIGSEGV approximately 140 seconds into the boot sequence. The greeter does not display. The crash is visible in dmesg: [140.093515] plasma-login-gr[2275]: segfault at 8e ip 00007ff359d532e4 sp 00007fff0cb6e7a8 error 4 in libQt6Gui.so.6.10.3[1532e4,7ff359c00000+795000] likely on CPU 1 (core 1, socket 0) fault address: 0x8e (error 4 = user-mode read from unmapped address) faulting IP: libQt6Gui.so.6 + 0x1532e4 = QWindow::screen() --- CRASH DETAILS Signal: SIGSEGV Fault addr: 0x8e (0xe == 14 == likely vtable offset dereference on freed/null object, classic use-after-free fingerprint) Crash site: QWindow::screen() -- qwindow.cpp:2261 Source at crash point (qt6-qtbase-6.10.3): // qwindow.cpp:2261 QScreen *QWindow::screen() const { Q_D(const QWindow); return d->parentWindow ? d->parentWindow->screen() // <-- CRASH : d->topLevelScreen.data(); } d = 0xe The d_func() macro expands to reinterpret_cast<const QWindowPrivate*>(d_ptr.d). A value of 0xe for d_ptr.d means the QWindow object's d-pointer is corrupt or freed. Dereferencing 0xe + offset of parentWindow (0x80 in QWindowPrivate) yields 0x8e, which matches the fault address exactly. --- FULL BACKTRACE -- THREAD 1 (crashing thread, LWP 2275) #0 QWindow::screen (this=<optimized out>) at qwindow.cpp:2261 d = 0xe <-- QWindowPrivate* is freed/corrupt #1 LoginGreeter::createWindowForScreen(QScreen*)::{lambda(QScreen*)#1} ::operator()(QScreen*) const at src/frontend/greeter/main.cpp:56 window = 0x55b1c5a67200 <-- captured QQuickWindow* (destroyed) screenRemoved = 0x7ff2f46dab80 <-- the removed QScreen* #2-#6 Qt slot dispatch machinery (QtPrivate::FunctorCall, QCallableObject::impl, QSlotObjectBase::call) #7 QtPrivate::QSlotObjectBase::call at qobjectdefs_impl.h:461 this = 0x55b1c59fe540 #8 doActivate<false> at qobject.cpp:4273 sender = 0x7fff0cb6f300 receiver = 0x7fff0cb6f340 signal_index (screenRemoved) = 10 #9 QMetaObject::activate at qobject.cpp:4333 #10 QGuiApplication::screenRemoved at moc_qguiapplication.cpp:313 _t1 = 0x7ff2f46dab80 <-- the QScreen being removed #11 QWindowSystemInterface::handleScreenRemoved at qcoreapplication.h:97 platformScreen = 0x7ff2f45ec660 screen = 0x7ff2f46dab80 newPrimaryScreen = 0x55b1c5993680 #12 QtWaylandClient::QWaylandDisplay::handleScreenInitialized at qwaylanddisplay.cpp:617 (note: screen initialization triggering screen *removal* -- see analysis) #13 QtWaylandClient::QWaylandScreen::maybeInitialize at qwaylandscreen.cpp:82 #14-#22 Wayland dispatch chain: ffi_call_unix64 / ffi_call_int / ffi_call wl_closure_invoke (libwayland-client.so.0) dispatch_event / wl_display_dispatch_queue_pending QtWaylandClient::EventThread::readAndDispatchEvents QObject::event / QCoreApplication::notifyInternal2 QCoreApplicationPrivate::sendPostedEvents postEventSourceDispatch / GLib main context dispatch #23 main at src/frontend/greeter/main.cpp:136 --- ROOT CAUSE ANALYSIS 1. WAYLAND OUTPUT NEGOTIATION DURING STARTUP The Wayland protocol requires multiple round-trips before a wl_output (screen) is considered fully initialized. Qt's Wayland platform plugin tracks this with a "pending screens" list and a set of required events (e.g., wl_output.geometry, wl_output.mode, wl_output.done). QWaylandScreen::maybeInitialize() (qwaylandscreen.cpp:73-82) checks whether all required events have been received. Once they have, QWaylandDisplay::handleScreenInitialized() is called. In handleScreenInitialized() (qwaylanddisplay.cpp:617), Qt may determine that the newly initialized output duplicates or replaces an existing screen (e.g., a placeholder created before geometry was known). In that case it calls QWindowSystemInterface::handleScreenRemoved() to remove the superseded screen before promoting the new one. This sequence fires the QGuiApplication::screenRemoved signal during the compositor's initial output negotiation phase -- even on single-monitor systems. It is not a multi-monitor scenario; it is a normal part of single-monitor Wayland startup on this hardware/compositor combination. 2. THE GREETER'S screenRemoved HANDLER In main.cpp, createWindowForScreen() creates a QQuickWindow per screen and connects a lambda to QGuiApplication::screenRemoved: // main.cpp:56 (reconstructed from backtrace symbols) connect(app, &QGuiApplication::screenRemoved, greeter, [window](QScreen *screenRemoved) { if (window->screen() == screenRemoved) { // <-- CRASH // presumably: close or move the window } }); The lambda captures window (a raw QQuickWindow*) by value. When screenRemoved fires for the placeholder screen during output negotiation, Qt may have already destroyed the QQuickWindow associated with that placeholder (QWindowSystemInterface::handleScreenRemoved triggers QWindow destruction for windows on the removed screen). By the time the lambda executes, window is a dangling pointer. Calling window->screen() dereferences d_ptr.d = 0xe and crashes. 3. WHY d = 0xe QObject stores its private data at d_ptr.d. When a QObject subclass is destroyed, the d-pointer is not explicitly zeroed. If the allocation is reclaimed and partially reused before the dangling pointer is accessed, d_ptr.d will contain whatever the allocator wrote there -- in this case 0xe, producing a fault at 0xe + offsetof(QWindowPrivate, parentWindow) = 0x8e, which matches the kernel's reported fault address exactly. --- SUGGESTED FIX Use QPointer<QQuickWindow> to safely detect window destruction before dereferencing: // main.cpp -- createWindowForScreen() QPointer<QQuickWindow> safeWindow = window; connect(app, &QGuiApplication::screenRemoved, greeter, [safeWindow](QScreen *screenRemoved) { if (!safeWindow) // window was already destroyed return; if (safeWindow->screen() == screenRemoved) { // handle screen removal } }); QPointer is automatically zeroed when the pointed-to QObject is destroyed, making the null check safe without requiring manual lifecycle management. Additionally, the connection should be disconnected or the lambda should become a no-op once the greeter has finished initializing, to avoid acting on screen topology changes that arrive after startup is complete. --- WORKAROUND None currently known that does not involve modifying the binary or compositor configuration. The crash occurs on every cold boot; warm reboots may or may not reproduce depending on compositor state at startup. --- REPRODUCTION 1. Cold boot on affected hardware (confirmed single-monitor Wayland system) 2. Observe greeter fail to display 3. Confirm via: journalctl -b | grep plasma-login-greeter dmesg | grep plasma-login-gr coredumpctl list Approximate time to crash from boot: 140 seconds (varies by hardware). --- CORE DUMP Captured via systemd-coredump. coredumpctl info 2275 Storage: /var/lib/systemd/coredump/ core.plasma-login-gr.967.<bootid>.2275.<timestamp>.zst Size: 8.4M (compressed) ```
cc: jgrulich@redhat.com at the Fedora KDE sig
Urgh, I see it: You would need to create screen A create screen B delete screen B (this is fine, but the connect is not bound and now the captured window is dangling) delete screen A (this now crashes evaluating the lambda set up for screen B) Using QPointer is a bad solution, we should scope the connect. *or* just pivot to letting layer shell dismiss the window and deleting on that.
A possibly relevant merge request was started @ https://invent.kde.org/plasma/plasma-login-manager/-/merge_requests/128
Git commit d4da6b79377756796081a19c1f628263b6e3a442 by Oliver Beard, on behalf of David Edmundson. Committed on 23/04/2026 at 14:40. Pushed by davidedmundson into branch 'master'. greeter: Avoid leaking connections for window destruction When a screen is removed we delete the window, because the connect was scoped to the greeter this connect lingered with the captured 'window' pointer dangling. We also dropped the geometry connection as this is done implicitly via layer-shell anyway. M +1 -4 src/frontend/greeter/main.cpp M +0 -4 src/frontend/wallpaper/wallpaperapp.cpp https://invent.kde.org/plasma/plasma-login-manager/-/commit/d4da6b79377756796081a19c1f628263b6e3a442
Hi. Thanks for the quick turnaround on this! I see it's committed to `master`. Looking at https://community.kde.org/Schedules/Plasma_6#Future_releases I see 6.6.5 Bugfix Release Tue 2026-05-12 I'm not sure where to look to check when this fix gets into Distro -- Fedora in my case; v43 right now, v44 any day now. Does this project push from master>6.6.5 , and then the Distro(s) pick that up on regular update schedule? Or does the Distro need to drive it? Maybe with a ping from me?
As I understand it Fedora are quick to pick up Plasma bugfix releases. Distros can cherry-pick commits before they land in a release. I'll recommend that we ask distros to cherry-pick this sooner after also looking at the wallpaper, as reports that users are left with a black screen implies that both are deficient.
Git commit b967468299bd28bffcfaad04cc4ee0485a80616e by Oliver Beard. Committed on 23/04/2026 at 19:34. Pushed by olib into branch 'Plasma/6.6'. greeter: Avoid leaking connections for window destruction When a screen is removed we delete the window, because the connect was scoped to the greeter this connect lingered with the captured 'window' pointer dangling. We also dropped the geometry connection as this is done implicitly via layer-shell anyway. (cherry picked from commit d4da6b79377756796081a19c1f628263b6e3a442) Co-authored-by: David Edmundson <kde@davidedmundson.co.uk> M +1 -4 src/frontend/greeter/main.cpp M +0 -4 src/frontend/wallpaper/wallpaperapp.cpp https://invent.kde.org/plasma/plasma-login-manager/-/commit/b967468299bd28bffcfaad04cc4ee0485a80616e
(In reply to Oliver Beard from comment #6) Hi. Ok, Thanks. It sounds like it gets done pretty much on auto-pilot. Just in case, I see in the Fedora pkg listing https://src.fedoraproject.org/rpms/plasma-login-manager it's mainted by 'ngompa'. I don't see them on the list here. I guess cc: for info won't hurt.