On EVERY system cold boot, the system boots to a blank screen.
It is functional @ shell, accessible via ssh, etc.; just the graphical env has an issue.
Checking dmesg I see
…
plasma-login-greeter segfault at 8e ip 00007f072e553124 sp 00007fff88e5e858 error 4 in libQt6Gui.so.6.10.2[153124,7f072e400000+797000] likely on CPU 1 (core 1, socket 0)
…
every time.
An immediate warm-reboot solves the problem. The system boots to greeter screen, login works, and the Plasma Desktop is up.
No error in dmesg this second time around.
I can reboot all day long and it’s good.
If I shutdown, then cold boot. It happens again, same error.
I don’t know much at all about debugging KDE packages yet.
Just want to first check if this is a known problem with a fix? Bad config maybe?
Or a real bug?
I was able to get a core dump.
Here’s a gdb report:
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=)
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
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
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.
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.
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 to safely detect window destruction before
dereferencing:
// main.cpp – createWindowForScreen()
QPointer 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
Cold boot on affected hardware (confirmed single-monitor Wayland system)
Observe greeter fail to display
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..2275..zst
Size: 8.4M (compressed)